From 12f0bd4e2deb286e97aa9736e6f08775d602581b Mon Sep 17 00:00:00 2001 From: Natty Date: Thu, 20 Apr 2023 20:17:44 +0200 Subject: [PATCH] Removed Mastodon API and messaging --- package.json | 4 +- packages/backend/package.json | 1 - packages/backend/src/db/postgre.ts | 2 - packages/backend/src/misc/api-permissions.ts | 2 - packages/backend/src/misc/schema.ts | 2 - .../src/models/entities/messaging-message.ts | 96 ----- packages/backend/src/models/index.ts | 2 - .../models/repositories/messaging-message.ts | 48 --- .../backend/src/models/repositories/user.ts | 40 -- .../src/models/schema/messaging-message.ts | 87 ---- packages/backend/src/models/schema/user.ts | 5 - .../src/remote/activitypub/db-resolver.ts | 21 - .../remote/activitypub/kernel/delete/note.ts | 12 +- .../src/remote/activitypub/kernel/index.ts | 3 - .../src/remote/activitypub/kernel/read.ts | 33 -- .../src/remote/activitypub/models/note.ts | 32 +- .../src/remote/activitypub/renderer/read.ts | 12 - packages/backend/src/server/activitypub.ts | 5 +- .../api/common/read-messaging-message.ts | 179 -------- packages/backend/src/server/api/endpoints.ts | 12 - .../i/read-all-messaging-messages.ts | 48 --- .../server/api/endpoints/messaging/history.ts | 112 ----- .../api/endpoints/messaging/messages.ts | 182 -------- .../endpoints/messaging/messages/create.ts | 165 ------- .../endpoints/messaging/messages/delete.ts | 48 --- .../api/endpoints/messaging/messages/read.ts | 57 --- packages/backend/src/server/api/index.ts | 3 - .../mastodon/ApiMastodonCompatibleService.ts | 58 --- .../server/api/mastodon/endpoints/account.ts | 323 -------------- .../src/server/api/mastodon/endpoints/auth.ts | 81 ---- .../server/api/mastodon/endpoints/filter.ts | 83 ---- .../src/server/api/mastodon/endpoints/meta.ts | 97 ----- .../api/mastodon/endpoints/notifications.ts | 89 ---- .../server/api/mastodon/endpoints/search.ts | 25 -- .../server/api/mastodon/endpoints/status.ts | 403 ------------------ .../server/api/mastodon/endpoints/timeline.ts | 246 ----------- .../src/server/api/stream/channels/index.ts | 4 - .../api/stream/channels/messaging-index.ts | 14 - .../server/api/stream/channels/messaging.ts | 130 ------ .../backend/src/server/api/stream/index.ts | 297 ++----------- .../backend/src/server/api/stream/types.ts | 38 -- packages/backend/src/server/index.ts | 30 -- .../backend/src/services/messages/create.ts | 148 ------- .../backend/src/services/messages/delete.ts | 50 --- .../backend/src/services/push-notification.ts | 3 - packages/backend/src/services/stream.ts | 49 --- packages/client/src/init.ts | 9 - packages/client/src/navbar.ts | 7 - packages/client/src/pages/messaging/index.vue | 220 ---------- .../pages/messaging/messaging-room.form.vue | 361 ---------------- .../messaging/messaging-room.message.vue | 329 -------------- .../src/pages/messaging/messaging-room.vue | 400 ----------------- packages/client/src/router.ts | 16 - packages/client/src/scripts/get-note-menu.ts | 3 +- packages/client/src/scripts/get-user-menu.ts | 9 - packages/client/src/store.ts | 1 - .../sw/src/scripts/create-notification.ts | 27 -- packages/sw/src/scripts/operations.ts | 13 - packages/sw/src/sw.ts | 30 -- packages/sw/src/types.ts | 3 - pnpm-lock.yaml | 358 ++++++++++++---- 61 files changed, 330 insertions(+), 4837 deletions(-) delete mode 100644 packages/backend/src/models/entities/messaging-message.ts delete mode 100644 packages/backend/src/models/repositories/messaging-message.ts delete mode 100644 packages/backend/src/models/schema/messaging-message.ts delete mode 100644 packages/backend/src/remote/activitypub/kernel/read.ts delete mode 100644 packages/backend/src/remote/activitypub/renderer/read.ts delete mode 100644 packages/backend/src/server/api/common/read-messaging-message.ts delete mode 100644 packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts delete mode 100644 packages/backend/src/server/api/endpoints/messaging/history.ts delete mode 100644 packages/backend/src/server/api/endpoints/messaging/messages.ts delete mode 100644 packages/backend/src/server/api/endpoints/messaging/messages/create.ts delete mode 100644 packages/backend/src/server/api/endpoints/messaging/messages/delete.ts delete mode 100644 packages/backend/src/server/api/endpoints/messaging/messages/read.ts delete mode 100644 packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/account.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/auth.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/filter.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/meta.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/notifications.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/search.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/status.ts delete mode 100644 packages/backend/src/server/api/mastodon/endpoints/timeline.ts delete mode 100644 packages/backend/src/server/api/stream/channels/messaging-index.ts delete mode 100644 packages/backend/src/server/api/stream/channels/messaging.ts delete mode 100644 packages/backend/src/services/messages/create.ts delete mode 100644 packages/backend/src/services/messages/delete.ts delete mode 100644 packages/client/src/pages/messaging/index.vue delete mode 100644 packages/client/src/pages/messaging/messaging-room.form.vue delete mode 100644 packages/client/src/pages/messaging/messaging-room.message.vue delete mode 100644 packages/client/src/pages/messaging/messaging-room.vue diff --git a/package.json b/package.json index 84749866d8..0463a12716 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "chokidar": "^3.3.1" }, "dependencies": { - "@bull-board/api": "^4.10.2", - "@bull-board/ui": "^4.10.2", + "@bull-board/api": "^4.12.2", + "@bull-board/ui": "^4.12.2", "@tensorflow/tfjs": "^3.21.0", "calckey-js": "^0.0.20", "js-yaml": "4.1.0", diff --git a/packages/backend/package.json b/packages/backend/package.json index 80484f95ce..90483a35e9 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -79,7 +79,6 @@ "koa-send": "5.0.1", "koa-slow": "2.1.0", "koa-views": "7.0.2", - "@cutls/megalodon": "5.1.15", "mfm-js": "0.23.2", "mime-types": "2.1.35", "multer": "1.4.4-lts.1", diff --git a/packages/backend/src/db/postgre.ts b/packages/backend/src/db/postgre.ts index f95bd2594d..9c86044777 100644 --- a/packages/backend/src/db/postgre.ts +++ b/packages/backend/src/db/postgre.ts @@ -34,7 +34,6 @@ import { Hashtag } from "@/models/entities/hashtag.js"; import { NoteFavorite } from "@/models/entities/note-favorite.js"; import { AbuseUserReport } from "@/models/entities/abuse-user-report.js"; import { RegistrationTicket } from "@/models/entities/registration-tickets.js"; -import { MessagingMessage } from "@/models/entities/messaging-message.js"; import { Signin } from "@/models/entities/signin.js"; import { AuthSession } from "@/models/entities/auth-session.js"; import { FollowRequest } from "@/models/entities/follow-request.js"; @@ -157,7 +156,6 @@ export const entities = [ SwSubscription, AbuseUserReport, RegistrationTicket, - MessagingMessage, Signin, ModerationLog, Clip, diff --git a/packages/backend/src/misc/api-permissions.ts b/packages/backend/src/misc/api-permissions.ts index 9e040262f1..bb4a842693 100644 --- a/packages/backend/src/misc/api-permissions.ts +++ b/packages/backend/src/misc/api-permissions.ts @@ -9,8 +9,6 @@ export const kinds = [ "write:favorites", "read:following", "write:following", - "read:messaging", - "write:messaging", "read:mutes", "write:mutes", "write:notes", diff --git a/packages/backend/src/misc/schema.ts b/packages/backend/src/misc/schema.ts index 35637e6ed5..65d199c3e3 100644 --- a/packages/backend/src/misc/schema.ts +++ b/packages/backend/src/misc/schema.ts @@ -10,7 +10,6 @@ import { import { packedNoteSchema } from "@/models/schema/note.js"; import { packedUserListSchema } from "@/models/schema/user-list.js"; import { packedAppSchema } from "@/models/schema/app.js"; -import { packedMessagingMessageSchema } from "@/models/schema/messaging-message.js"; import { packedNotificationSchema } from "@/models/schema/notification.js"; import { packedDriveFileSchema } from "@/models/schema/drive-file.js"; import { packedDriveFolderSchema } from "@/models/schema/drive-folder.js"; @@ -42,7 +41,6 @@ export const refs = { UserList: packedUserListSchema, UserGroup: packedUserGroupSchema, App: packedAppSchema, - MessagingMessage: packedMessagingMessageSchema, Note: packedNoteSchema, NoteReaction: packedNoteReactionSchema, NoteFavorite: packedNoteFavoriteSchema, diff --git a/packages/backend/src/models/entities/messaging-message.ts b/packages/backend/src/models/entities/messaging-message.ts deleted file mode 100644 index 9cf197fa3b..0000000000 --- a/packages/backend/src/models/entities/messaging-message.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { - PrimaryColumn, - Entity, - Index, - JoinColumn, - Column, - ManyToOne, -} from "typeorm"; -import { User } from "./user.js"; -import { DriveFile } from "./drive-file.js"; -import { id } from "../id.js"; -import { UserGroup } from "./user-group.js"; - -@Entity() -export class MessagingMessage { - @PrimaryColumn(id()) - public id: string; - - @Index() - @Column('timestamp with time zone', { - comment: 'The created date of the MessagingMessage.', - }) - public createdAt: Date; - - @Index() - @Column({ - ...id(), - comment: 'The sender user ID.', - }) - public userId: User["id"]; - - @ManyToOne(type => User, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public user: User | null; - - @Index() - @Column({ - ...id(), nullable: true, - comment: 'The recipient user ID.', - }) - public recipientId: User["id"] | null; - - @ManyToOne(type => User, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public recipient: User | null; - - @Index() - @Column({ - ...id(), nullable: true, - comment: 'The recipient group ID.', - }) - public groupId: UserGroup["id"] | null; - - @ManyToOne(type => UserGroup, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public group: UserGroup | null; - - @Column('varchar', { - length: 4096, nullable: true, - }) - public text: string | null; - - @Column('boolean', { - default: false, - }) - public isRead: boolean; - - @Column('varchar', { - length: 512, nullable: true, - }) - public uri: string | null; - - @Column({ - ...id(), - array: true, default: '{}', - }) - public reads: User["id"][]; - - @Column({ - ...id(), - nullable: true, - }) - public fileId: DriveFile["id"] | null; - - @ManyToOne(type => DriveFile, { - onDelete: 'CASCADE', - }) - @JoinColumn() - public file: DriveFile | null; -} diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index 98f6705f42..2bfd6d8b8b 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -19,7 +19,6 @@ import { DriveFolderRepository } from "./repositories/drive-folder.js"; import { AccessToken } from "./entities/access-token.js"; import { UserNotePining } from "./entities/user-note-pining.js"; import { SigninRepository } from "./repositories/signin.js"; -import { MessagingMessageRepository } from "./repositories/messaging-message.js"; import { UserListRepository } from "./repositories/user-list.js"; import { UserListJoining } from "./entities/user-list-joining.js"; import { UserGroupRepository } from "./repositories/user-group.js"; @@ -110,7 +109,6 @@ export const RegistrationTickets = db.getRepository(RegistrationTicket); export const AuthSessions = AuthSessionRepository; export const AccessTokens = db.getRepository(AccessToken); export const Signins = SigninRepository; -export const MessagingMessages = MessagingMessageRepository; export const Pages = PageRepository; export const PageLikes = PageLikeRepository; export const GalleryPosts = GalleryPostRepository; diff --git a/packages/backend/src/models/repositories/messaging-message.ts b/packages/backend/src/models/repositories/messaging-message.ts deleted file mode 100644 index 6c0987bf08..0000000000 --- a/packages/backend/src/models/repositories/messaging-message.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { db } from "@/db/postgre.js"; -import { MessagingMessage } from "@/models/entities/messaging-message.js"; -import { Users, DriveFiles, UserGroups } from "../index.js"; -import type { Packed } from "@/misc/schema.js"; -import type { User } from "@/models/entities/user.js"; - -export const MessagingMessageRepository = db - .getRepository(MessagingMessage) - .extend({ - async pack( - src: MessagingMessage["id"] | MessagingMessage, - me?: { id: User["id"] } | null | undefined, - options?: { - populateRecipient?: boolean; - populateGroup?: boolean; - }, - ): Promise> { - const opts = options || { - populateRecipient: true, - populateGroup: true, - }; - - const message = - typeof src === "object" ? src : await this.findOneByOrFail({ id: src }); - - return { - id: message.id, - createdAt: message.createdAt.toISOString(), - text: message.text, - userId: message.userId, - user: await Users.pack(message.user || message.userId, me), - recipientId: message.recipientId, - recipient: - message.recipientId && opts.populateRecipient - ? await Users.pack(message.recipient || message.recipientId, me) - : undefined, - groupId: message.groupId, - group: - message.groupId && opts.populateGroup - ? await UserGroups.pack(message.group || message.groupId) - : undefined, - fileId: message.fileId, - file: message.fileId ? await DriveFiles.pack(message.fileId) : null, - isRead: message.isRead, - reads: message.reads, - }; - }, - }); diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts index aa224b6674..b9913a5c15 100644 --- a/packages/backend/src/models/repositories/user.ts +++ b/packages/backend/src/models/repositories/user.ts @@ -26,7 +26,6 @@ import { Followings, FollowRequests, Instances, - MessagingMessages, Mutings, Notes, NoteUnreads, @@ -174,42 +173,6 @@ export const UserRepository = db.getRepository(User).extend({ }); }, - async getHasUnreadMessagingMessage(userId: User["id"]): Promise { - const mute = await Mutings.findBy({ - muterId: userId, - }); - - const joinings = await UserGroupJoinings.findBy({ userId: userId }); - - const groupQs = Promise.all( - joinings.map((j) => - MessagingMessages.createQueryBuilder("message") - .where("message.groupId = :groupId", { groupId: j.userGroupId }) - .andWhere("message.userId != :userId", { userId: userId }) - .andWhere("NOT (:userId = ANY(message.reads))", { userId: userId }) - .andWhere("message.createdAt > :joinedAt", { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない - .getOne() - .then((x) => x != null), - ), - ); - - const [withUser, withGroups] = await Promise.all([ - MessagingMessages.count({ - where: { - recipientId: userId, - isRead: false, - ...(mute.length > 0 - ? { userId: Not(In(mute.map((x) => x.muteeId))) } - : {}), - }, - take: 1, - }).then((count) => count > 0), - groupQs, - ]); - - return withUser || withGroups.some((x) => x); - }, - async getHasUnreadAnnouncement(userId: User["id"]): Promise { const reads = await AnnouncementReads.findBy({ userId: userId, @@ -540,9 +503,6 @@ export const UserRepository = db.getRepository(User).extend({ hasUnreadAnnouncement: this.getHasUnreadAnnouncement(user.id), hasUnreadAntenna: this.getHasUnreadAntenna(user.id), hasUnreadChannel: this.getHasUnreadChannel(user.id), - hasUnreadMessagingMessage: this.getHasUnreadMessagingMessage( - user.id, - ), hasUnreadNotification: this.getHasUnreadNotification(user.id), hasPendingReceivedFollowRequest: this.getHasPendingReceivedFollowRequest(user.id), diff --git a/packages/backend/src/models/schema/messaging-message.ts b/packages/backend/src/models/schema/messaging-message.ts deleted file mode 100644 index d598e6dbc6..0000000000 --- a/packages/backend/src/models/schema/messaging-message.ts +++ /dev/null @@ -1,87 +0,0 @@ -export const packedMessagingMessageSchema = { - type: "object", - properties: { - id: { - type: "string", - optional: false, - nullable: false, - format: "id", - example: "xxxxxxxxxx", - }, - createdAt: { - type: "string", - optional: false, - nullable: false, - format: "date-time", - }, - userId: { - type: "string", - optional: false, - nullable: false, - format: "id", - }, - user: { - type: "object", - ref: "UserLite", - optional: true, - nullable: false, - }, - text: { - type: "string", - optional: false, - nullable: true, - }, - fileId: { - type: "string", - optional: true, - nullable: true, - format: "id", - }, - file: { - type: "object", - optional: true, - nullable: true, - ref: "DriveFile", - }, - recipientId: { - type: "string", - optional: false, - nullable: true, - format: "id", - }, - recipient: { - type: "object", - optional: true, - nullable: true, - ref: "UserLite", - }, - groupId: { - type: "string", - optional: false, - nullable: true, - format: "id", - }, - group: { - type: "object", - optional: true, - nullable: true, - ref: "UserGroup", - }, - isRead: { - type: "boolean", - optional: true, - nullable: false, - }, - reads: { - type: "array", - optional: true, - nullable: false, - items: { - type: "string", - optional: false, - nullable: false, - format: "id", - }, - }, - }, -} as const; diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts index 9fb5aa8f3b..30fcc87e52 100644 --- a/packages/backend/src/models/schema/user.ts +++ b/packages/backend/src/models/schema/user.ts @@ -424,11 +424,6 @@ export const packedMeDetailedOnlySchema = { nullable: false, optional: false, }, - hasUnreadMessagingMessage: { - type: "boolean", - nullable: false, - optional: false, - }, hasUnreadNotification: { type: "boolean", nullable: false, diff --git a/packages/backend/src/remote/activitypub/db-resolver.ts b/packages/backend/src/remote/activitypub/db-resolver.ts index 0a2aec9e85..b8665b2459 100644 --- a/packages/backend/src/remote/activitypub/db-resolver.ts +++ b/packages/backend/src/remote/activitypub/db-resolver.ts @@ -5,14 +5,11 @@ import type { CacheableRemoteUser, CacheableUser, } from "@/models/entities/user.js"; -import { User, IRemoteUser } from "@/models/entities/user.js"; import type { UserPublickey } from "@/models/entities/user-publickey.js"; -import type { MessagingMessage } from "@/models/entities/messaging-message.js"; import { Notes, Users, UserPublickeys, - MessagingMessages, } from "@/models/index.js"; import { Cache } from "@/misc/cache.js"; import { uriPersonCache, userByIdCache } from "@/services/user-cache.js"; @@ -88,24 +85,6 @@ export default class DbResolver { } } - public async getMessageFromApId( - value: string | IObject, - ): Promise { - const parsed = parseUri(value); - - if (parsed.local) { - if (parsed.type !== "notes") return null; - - return await MessagingMessages.findOneBy({ - id: parsed.id, - }); - } else { - return await MessagingMessages.findOneBy({ - uri: parsed.uri, - }); - } - } - /** * AP Person => Misskey User in DB */ diff --git a/packages/backend/src/remote/activitypub/kernel/delete/note.ts b/packages/backend/src/remote/activitypub/kernel/delete/note.ts index 69298e9175..c15aa8bebc 100644 --- a/packages/backend/src/remote/activitypub/kernel/delete/note.ts +++ b/packages/backend/src/remote/activitypub/kernel/delete/note.ts @@ -3,7 +3,6 @@ import deleteNode from "@/services/note/delete.js"; import { apLogger } from "../../logger.js"; import DbResolver from "../../db-resolver.js"; import { getApLock } from "@/misc/app-lock.js"; -import { deleteMessage } from "@/services/messages/delete.js"; const logger = apLogger; @@ -20,16 +19,7 @@ export default async function ( const note = await dbResolver.getNoteFromApId(uri); if (note == null) { - const message = await dbResolver.getMessageFromApId(uri); - if (message == null) return "message not found"; - - if (message.userId !== actor.id) { - return "The user trying to delete the post is not the post author"; - } - - await deleteMessage(message); - - return "ok: message deleted"; + return "ok: note is null"; } if (note.userId !== actor.id) { diff --git a/packages/backend/src/remote/activitypub/kernel/index.ts b/packages/backend/src/remote/activitypub/kernel/index.ts index 58e354a512..8e70355ca7 100644 --- a/packages/backend/src/remote/activitypub/kernel/index.ts +++ b/packages/backend/src/remote/activitypub/kernel/index.ts @@ -25,7 +25,6 @@ import Resolver from "../resolver.js"; import create from "./create/index.js"; import performDeleteActivity from "./delete/index.js"; import performUpdateActivity from "./update/index.js"; -import { performReadActivity } from "./read.js"; import follow from "./follow.js"; import undo from "./undo/index.js"; import like from "./like.js"; @@ -81,8 +80,6 @@ async function performOneActivity( await performDeleteActivity(actor, activity); } else if (isUpdate(activity)) { await performUpdateActivity(actor, activity); - } else if (isRead(activity)) { - await performReadActivity(actor, activity); } else if (isFollow(activity)) { await follow(actor, activity); } else if (isAccept(activity)) { diff --git a/packages/backend/src/remote/activitypub/kernel/read.ts b/packages/backend/src/remote/activitypub/kernel/read.ts deleted file mode 100644 index 7cc70976c3..0000000000 --- a/packages/backend/src/remote/activitypub/kernel/read.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { CacheableRemoteUser } from "@/models/entities/user.js"; -import type { IRead } from "../type.js"; -import { getApId } from "../type.js"; -import { isSelfHost, extractDbHost } from "@/misc/convert-host.js"; -import { MessagingMessages } from "@/models/index.js"; -import { readUserMessagingMessage } from "../../../server/api/common/read-messaging-message.js"; - -export const performReadActivity = async ( - actor: CacheableRemoteUser, - activity: IRead, -): Promise => { - const id = await getApId(activity.object); - - if (!isSelfHost(extractDbHost(id))) { - return `skip: Read to foreign host (${id})`; - } - - const messageId = id.split("/").pop(); - - const message = await MessagingMessages.findOneBy({ id: messageId }); - if (message == null) { - return "skip: message not found"; - } - - if (actor.id !== message.recipientId) { - return "skip: actor is not a message recipient"; - } - - await readUserMessagingMessage(message.recipientId!, message.userId, [ - message.id, - ]); - return `ok: mark as read (${message.userId} => ${message.recipientId} ${message.id})`; -}; diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 34d8d0ba16..ea6dfcc6e4 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -15,7 +15,7 @@ import { apLogger } from "../logger.js"; import type { DriveFile } from "@/models/entities/drive-file.js"; import { deliverQuestionUpdate } from "@/services/note/polls/update.js"; import { extractDbHost, toPuny } from "@/misc/convert-host.js"; -import { Emojis, Polls, MessagingMessages } from "@/models/index.js"; +import { Emojis, Polls } from "@/models/index.js"; import type { Note } from "@/models/entities/note.js"; import type { IObject, IPost } from "../type.js"; import { @@ -30,7 +30,6 @@ import type { Emoji } from "@/models/entities/emoji.js"; import { genId } from "@/misc/gen-id.js"; import { fetchMeta } from "@/misc/fetch-meta.js"; import { getApLock } from "@/misc/app-lock.js"; -import { createMessage } from "@/services/messages/create.js"; import { parseAudience } from "../audience.js"; import { extractApMentions } from "./mention.js"; import DbResolver from "../db-resolver.js"; @@ -152,6 +151,10 @@ export async function createNote( let isTalk = note._misskey_talk && visibility === "specified"; + if (isTalk) { + return null; + } + const apMentions = await extractApMentions(note.tag); const apHashtags = await extractApHashtags(note.tag); @@ -190,17 +193,6 @@ export async function createNote( } }) .catch(async (e) => { - // トークだったらinReplyToのエラーは無視 - const uri = getApId(note.inReplyTo); - if (uri.startsWith(`${config.url}/`)) { - const id = uri.split("/").pop(); - const talk = await MessagingMessages.findOneBy({ id }); - if (talk) { - isTalk = true; - return null; - } - } - logger.warn( `Error in inReplyTo ${note.inReplyTo} - ${e.statusCode || e}`, ); @@ -323,20 +315,6 @@ export async function createNote( () => undefined, ); - if (isTalk) { - for (const recipient of visibleUsers) { - await createMessage( - actor, - recipient, - undefined, - text || undefined, - files && files.length > 0 ? files[0] : null, - object.id, - ); - return null; - } - } - return await post( actor, { diff --git a/packages/backend/src/remote/activitypub/renderer/read.ts b/packages/backend/src/remote/activitypub/renderer/read.ts deleted file mode 100644 index 212e7e8ddf..0000000000 --- a/packages/backend/src/remote/activitypub/renderer/read.ts +++ /dev/null @@ -1,12 +0,0 @@ -import config from "@/config/index.js"; -import type { User } from "@/models/entities/user.js"; -import type { MessagingMessage } from "@/models/entities/messaging-message.js"; - -export const renderReadActivity = ( - user: { id: User["id"] }, - message: MessagingMessage, -) => ({ - type: "Read", - actor: `${config.url}/users/${user.id}`, - object: message.uri, -}); diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts index 29ac726efc..a858d9662a 100644 --- a/packages/backend/src/server/activitypub.ts +++ b/packages/backend/src/server/activitypub.ts @@ -22,13 +22,14 @@ import Featured from "./activitypub/featured.js"; import Following from "./activitypub/following.js"; import Followers from "./activitypub/followers.js"; import Outbox, { packActivity } from "./activitypub/outbox.js"; +import {IActivity} from "@/remote/activitypub/type"; // Init router const router = new Router(); //#region Routing -function inbox(ctx: Router.RouterContext) { +async function inbox(ctx: Router.RouterContext) { let signature; try { @@ -38,7 +39,7 @@ function inbox(ctx: Router.RouterContext) { return; } - processInbox(ctx.request.body, signature); + processInbox(ctx.request.body as IActivity, signature); ctx.status = 202; } diff --git a/packages/backend/src/server/api/common/read-messaging-message.ts b/packages/backend/src/server/api/common/read-messaging-message.ts deleted file mode 100644 index fc22c843af..0000000000 --- a/packages/backend/src/server/api/common/read-messaging-message.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { - publishMainStream, - publishGroupMessagingStream, -} from "@/services/stream.js"; -import { publishMessagingStream } from "@/services/stream.js"; -import { publishMessagingIndexStream } from "@/services/stream.js"; -import { pushNotification } from "@/services/push-notification.js"; -import type { User, IRemoteUser } from "@/models/entities/user.js"; -import type { MessagingMessage } from "@/models/entities/messaging-message.js"; -import { MessagingMessages, UserGroupJoinings, Users } from "@/models/index.js"; -import { In } from "typeorm"; -import { IdentifiableError } from "@/misc/identifiable-error.js"; -import type { UserGroup } from "@/models/entities/user-group.js"; -import { toArray } from "@/prelude/array.js"; -import { renderReadActivity } from "@/remote/activitypub/renderer/read.js"; -import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import { deliver } from "@/queue/index.js"; -import orderedCollection from "@/remote/activitypub/renderer/ordered-collection.js"; - -/** - * Mark messages as read - */ -export async function readUserMessagingMessage( - userId: User["id"], - otherpartyId: User["id"], - messageIds: MessagingMessage["id"][], -) { - if (messageIds.length === 0) return; - - const messages = await MessagingMessages.findBy({ - id: In(messageIds), - }); - - for (const message of messages) { - if (message.recipientId !== userId) { - throw new IdentifiableError( - "e140a4bf-49ce-4fb6-b67c-b78dadf6b52f", - "Access denied (user).", - ); - } - } - - // Update documents - await MessagingMessages.update( - { - id: In(messageIds), - userId: otherpartyId, - recipientId: userId, - isRead: false, - }, - { - isRead: true, - }, - ); - - // Publish event - publishMessagingStream(otherpartyId, userId, "read", messageIds); - publishMessagingIndexStream(userId, "read", messageIds); - - if (!(await Users.getHasUnreadMessagingMessage(userId))) { - // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 - publishMainStream(userId, "readAllMessagingMessages"); - pushNotification(userId, "readAllMessagingMessages", undefined); - } else { - // そのユーザーとのメッセージで未読がなければイベント発行 - const count = await MessagingMessages.count({ - where: { - userId: otherpartyId, - recipientId: userId, - isRead: false, - }, - take: 1, - }); - - if (!count) { - pushNotification(userId, "readAllMessagingMessagesOfARoom", { - userId: otherpartyId, - }); - } - } -} - -/** - * Mark messages as read - */ -export async function readGroupMessagingMessage( - userId: User["id"], - groupId: UserGroup["id"], - messageIds: MessagingMessage["id"][], -) { - if (messageIds.length === 0) return; - - // check joined - const joining = await UserGroupJoinings.findOneBy({ - userId: userId, - userGroupId: groupId, - }); - - if (joining == null) { - throw new IdentifiableError( - "930a270c-714a-46b2-b776-ad27276dc569", - "Access denied (group).", - ); - } - - const messages = await MessagingMessages.findBy({ - id: In(messageIds), - }); - - const reads: MessagingMessage["id"][] = []; - - for (const message of messages) { - if (message.userId === userId) continue; - if (message.reads.includes(userId)) continue; - - // Update document - await MessagingMessages.createQueryBuilder() - .update() - .set({ - reads: (() => `array_append("reads", '${joining.userId}')`) as any, - }) - .where("id = :id", { id: message.id }) - .execute(); - - reads.push(message.id); - } - - // Publish event - publishGroupMessagingStream(groupId, "read", { - ids: reads, - userId: userId, - }); - publishMessagingIndexStream(userId, "read", reads); - - if (!(await Users.getHasUnreadMessagingMessage(userId))) { - // 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行 - publishMainStream(userId, "readAllMessagingMessages"); - pushNotification(userId, "readAllMessagingMessages", undefined); - } else { - // そのグループにおいて未読がなければイベント発行 - const unreadExist = await MessagingMessages.createQueryBuilder("message") - .where("message.groupId = :groupId", { groupId: groupId }) - .andWhere("message.userId != :userId", { userId: userId }) - .andWhere("NOT (:userId = ANY(message.reads))", { userId: userId }) - .andWhere("message.createdAt > :joinedAt", { - joinedAt: joining.createdAt, - }) // 自分が加入する前の会話については、未読扱いしない - .getOne() - .then((x) => x != null); - - if (!unreadExist) { - pushNotification(userId, "readAllMessagingMessagesOfARoom", { groupId }); - } - } -} - -export async function deliverReadActivity( - user: { id: User["id"]; host: null }, - recipient: IRemoteUser, - messages: MessagingMessage | MessagingMessage[], -) { - messages = toArray(messages).filter((x) => x.uri); - const contents = messages.map((x) => renderReadActivity(user, x)); - - if (contents.length > 1) { - const collection = orderedCollection( - null, - contents.length, - undefined, - undefined, - contents, - ); - deliver(user, renderActivity(collection), recipient.inbox); - } else { - for (const content of contents) { - deliver(user, renderActivity(content), recipient.inbox); - } - } -} diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 353f137a76..8c16e0dc92 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -192,7 +192,6 @@ import * as ep___i_notifications from "./endpoints/i/notifications.js"; import * as ep___i_pageLikes from "./endpoints/i/page-likes.js"; import * as ep___i_pages from "./endpoints/i/pages.js"; import * as ep___i_pin from "./endpoints/i/pin.js"; -import * as ep___i_readAllMessagingMessages from "./endpoints/i/read-all-messaging-messages.js"; import * as ep___i_readAllUnreadNotes from "./endpoints/i/read-all-unread-notes.js"; import * as ep___i_readAnnouncement from "./endpoints/i/read-announcement.js"; import * as ep___i_regenerateToken from "./endpoints/i/regenerate-token.js"; @@ -216,11 +215,6 @@ import * as ep___i_webhooks_show from "./endpoints/i/webhooks/show.js"; import * as ep___i_webhooks_list from "./endpoints/i/webhooks/list.js"; import * as ep___i_webhooks_update from "./endpoints/i/webhooks/update.js"; import * as ep___i_webhooks_delete from "./endpoints/i/webhooks/delete.js"; -import * as ep___messaging_history from "./endpoints/messaging/history.js"; -import * as ep___messaging_messages from "./endpoints/messaging/messages.js"; -import * as ep___messaging_messages_create from "./endpoints/messaging/messages/create.js"; -import * as ep___messaging_messages_delete from "./endpoints/messaging/messages/delete.js"; -import * as ep___messaging_messages_read from "./endpoints/messaging/messages/read.js"; import * as ep___meta from "./endpoints/meta.js"; import * as ep___miauth_genToken from "./endpoints/miauth/gen-token.js"; import * as ep___mute_create from "./endpoints/mute/create.js"; @@ -533,7 +527,6 @@ const eps = [ ["i/page-likes", ep___i_pageLikes], ["i/pages", ep___i_pages], ["i/pin", ep___i_pin], - ["i/read-all-messaging-messages", ep___i_readAllMessagingMessages], ["i/read-all-unread-notes", ep___i_readAllUnreadNotes], ["i/read-announcement", ep___i_readAnnouncement], ["i/regenerate-token", ep___i_regenerateToken], @@ -557,11 +550,6 @@ const eps = [ ["i/webhooks/show", ep___i_webhooks_show], ["i/webhooks/update", ep___i_webhooks_update], ["i/webhooks/delete", ep___i_webhooks_delete], - ["messaging/history", ep___messaging_history], - ["messaging/messages", ep___messaging_messages], - ["messaging/messages/create", ep___messaging_messages_create], - ["messaging/messages/delete", ep___messaging_messages_delete], - ["messaging/messages/read", ep___messaging_messages_read], ["meta", ep___meta], ["miauth/gen-token", ep___miauth_genToken], ["mute/create", ep___mute_create], diff --git a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts b/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts deleted file mode 100644 index 0333677275..0000000000 --- a/packages/backend/src/server/api/endpoints/i/read-all-messaging-messages.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { publishMainStream } from "@/services/stream.js"; -import define from "../../define.js"; -import { MessagingMessages, UserGroupJoinings } from "@/models/index.js"; - -export const meta = { - tags: ["account", "messaging"], - - requireCredential: true, - - kind: "write:account", -} as const; - -export const paramDef = { - type: "object", - properties: {}, - required: [], -} as const; - -export default define(meta, paramDef, async (ps, user) => { - // Update documents - await MessagingMessages.update( - { - recipientId: user.id, - isRead: false, - }, - { - isRead: true, - }, - ); - - const joinings = await UserGroupJoinings.findBy({ userId: user.id }); - - await Promise.all( - joinings.map((j) => - MessagingMessages.createQueryBuilder() - .update() - .set({ - reads: (() => `array_append("reads", '${user.id}')`) as any, - }) - .where("groupId = :groupId", { groupId: j.userGroupId }) - .andWhere("userId != :userId", { userId: user.id }) - .andWhere("NOT (:userId = ANY(reads))", { userId: user.id }) - .execute(), - ), - ); - - publishMainStream(user.id, "readAllMessagingMessages"); -}); diff --git a/packages/backend/src/server/api/endpoints/messaging/history.ts b/packages/backend/src/server/api/endpoints/messaging/history.ts deleted file mode 100644 index 7d1df69850..0000000000 --- a/packages/backend/src/server/api/endpoints/messaging/history.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { Brackets } from "typeorm"; -import type { MessagingMessage } from "@/models/entities/messaging-message.js"; -import { - MessagingMessages, - Mutings, - UserGroupJoinings, -} from "@/models/index.js"; -import define from "../../define.js"; - -export const meta = { - tags: ["messaging"], - - requireCredential: true, - - kind: "read:messaging", - - res: { - type: "array", - optional: false, - nullable: false, - items: { - type: "object", - optional: false, - nullable: false, - ref: "MessagingMessage", - }, - }, -} as const; - -export const paramDef = { - type: "object", - properties: { - limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, - group: { type: "boolean", default: false }, - }, - required: [], -} as const; - -export default define(meta, paramDef, async (ps, user) => { - const mute = await Mutings.findBy({ - muterId: user.id, - }); - - const groups = ps.group - ? await UserGroupJoinings.findBy({ - userId: user.id, - }).then((xs) => xs.map((x) => x.userGroupId)) - : []; - - if (ps.group && groups.length === 0) { - return []; - } - - const history: MessagingMessage[] = []; - - for (let i = 0; i < ps.limit; i++) { - const found = ps.group - ? history.map((m) => m.groupId!) - : history.map((m) => (m.userId === user.id ? m.recipientId! : m.userId!)); - - const query = MessagingMessages.createQueryBuilder("message").orderBy( - "message.createdAt", - "DESC", - ); - - if (ps.group) { - query.where("message.groupId IN (:...groups)", { groups: groups }); - - if (found.length > 0) { - query.andWhere("message.groupId NOT IN (:...found)", { found: found }); - } - } else { - query.where( - new Brackets((qb) => { - qb.where("message.userId = :userId", { userId: user.id }).orWhere( - "message.recipientId = :userId", - { userId: user.id }, - ); - }), - ); - query.andWhere("message.groupId IS NULL"); - - if (found.length > 0) { - query.andWhere("message.userId NOT IN (:...found)", { found: found }); - query.andWhere("message.recipientId NOT IN (:...found)", { - found: found, - }); - } - - if (mute.length > 0) { - query.andWhere("message.userId NOT IN (:...mute)", { - mute: mute.map((m) => m.muteeId), - }); - query.andWhere("message.recipientId NOT IN (:...mute)", { - mute: mute.map((m) => m.muteeId), - }); - } - } - - const message = await query.getOne(); - - if (message) { - history.push(message); - } else { - break; - } - } - - return await Promise.all( - history.map((h) => MessagingMessages.pack(h.id, user)), - ); -}); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages.ts b/packages/backend/src/server/api/endpoints/messaging/messages.ts deleted file mode 100644 index 4b5440383c..0000000000 --- a/packages/backend/src/server/api/endpoints/messaging/messages.ts +++ /dev/null @@ -1,182 +0,0 @@ -import define from "../../define.js"; -import { ApiError } from "../../error.js"; -import { getUser } from "../../common/getters.js"; -import { - MessagingMessages, - UserGroups, - UserGroupJoinings, - Users, -} from "@/models/index.js"; -import { makePaginationQuery } from "../../common/make-pagination-query.js"; -import { Brackets } from "typeorm"; -import { - readUserMessagingMessage, - readGroupMessagingMessage, - deliverReadActivity, -} from "../../common/read-messaging-message.js"; - -export const meta = { - tags: ["messaging"], - - requireCredential: true, - - kind: "read:messaging", - - res: { - type: "array", - optional: false, - nullable: false, - items: { - type: "object", - optional: false, - nullable: false, - ref: "MessagingMessage", - }, - }, - - errors: { - noSuchUser: { - message: "No such user.", - code: "NO_SUCH_USER", - id: "11795c64-40ea-4198-b06e-3c873ed9039d", - }, - - noSuchGroup: { - message: "No such group.", - code: "NO_SUCH_GROUP", - id: "c4d9f88c-9270-4632-b032-6ed8cee36f7f", - }, - - groupAccessDenied: { - message: "You can not read messages of groups that you have not joined.", - code: "GROUP_ACCESS_DENIED", - id: "a053a8dd-a491-4718-8f87-50775aad9284", - }, - }, -} as const; - -export const paramDef = { - type: "object", - properties: { - limit: { type: "integer", minimum: 1, maximum: 100, default: 10 }, - sinceId: { type: "string", format: "misskey:id" }, - untilId: { type: "string", format: "misskey:id" }, - markAsRead: { type: "boolean", default: true }, - }, - anyOf: [ - { - properties: { - userId: { type: "string", format: "misskey:id" }, - }, - required: ["userId"], - }, - { - properties: { - groupId: { type: "string", format: "misskey:id" }, - }, - required: ["groupId"], - }, - ], -} as const; - -export default define(meta, paramDef, async (ps, user) => { - if (ps.userId != null) { - // Fetch recipient (user) - const recipient = await getUser(ps.userId).catch((e) => { - if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") - throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - const query = makePaginationQuery( - MessagingMessages.createQueryBuilder("message"), - ps.sinceId, - ps.untilId, - ) - .andWhere( - new Brackets((qb) => { - qb.where( - new Brackets((qb) => { - qb.where("message.userId = :meId").andWhere( - "message.recipientId = :recipientId", - ); - }), - ).orWhere( - new Brackets((qb) => { - qb.where("message.userId = :recipientId").andWhere( - "message.recipientId = :meId", - ); - }), - ); - }), - ) - .setParameter("meId", user.id) - .setParameter("recipientId", recipient.id); - - const messages = await query.take(ps.limit).getMany(); - - // Mark all as read - if (ps.markAsRead) { - readUserMessagingMessage( - user.id, - recipient.id, - messages.filter((m) => m.recipientId === user.id).map((x) => x.id), - ); - - // リモートユーザーとのメッセージだったら既読配信 - if (Users.isLocalUser(user) && Users.isRemoteUser(recipient)) { - deliverReadActivity(user, recipient, messages); - } - } - - return await Promise.all( - messages.map((message) => - MessagingMessages.pack(message, user, { - populateRecipient: false, - }), - ), - ); - } else if (ps.groupId != null) { - // Fetch recipient (group) - const recipientGroup = await UserGroups.findOneBy({ id: ps.groupId }); - - if (recipientGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - // check joined - const joining = await UserGroupJoinings.findOneBy({ - userId: user.id, - userGroupId: recipientGroup.id, - }); - - if (joining == null) { - throw new ApiError(meta.errors.groupAccessDenied); - } - - const query = makePaginationQuery( - MessagingMessages.createQueryBuilder("message"), - ps.sinceId, - ps.untilId, - ).andWhere("message.groupId = :groupId", { groupId: recipientGroup.id }); - - const messages = await query.take(ps.limit).getMany(); - - // Mark all as read - if (ps.markAsRead) { - readGroupMessagingMessage( - user.id, - recipientGroup.id, - messages.map((x) => x.id), - ); - } - - return await Promise.all( - messages.map((message) => - MessagingMessages.pack(message, user, { - populateGroup: false, - }), - ), - ); - } -}); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts b/packages/backend/src/server/api/endpoints/messaging/messages/create.ts deleted file mode 100644 index 99d392ce45..0000000000 --- a/packages/backend/src/server/api/endpoints/messaging/messages/create.ts +++ /dev/null @@ -1,165 +0,0 @@ -import define from "../../../define.js"; -import { ApiError } from "../../../error.js"; -import { getUser } from "../../../common/getters.js"; -import { - MessagingMessages, - DriveFiles, - UserGroups, - UserGroupJoinings, - Blockings, -} from "@/models/index.js"; -import type { User } from "@/models/entities/user.js"; -import type { UserGroup } from "@/models/entities/user-group.js"; -import { createMessage } from "@/services/messages/create.js"; - -export const meta = { - tags: ["messaging"], - - requireCredential: true, - - kind: "write:messaging", - - res: { - type: "object", - optional: false, - nullable: false, - ref: "MessagingMessage", - }, - - errors: { - recipientIsYourself: { - message: "You can not send a message to yourself.", - code: "RECIPIENT_IS_YOURSELF", - id: "17e2ba79-e22a-4cbc-bf91-d327643f4a7e", - }, - - noSuchUser: { - message: "No such user.", - code: "NO_SUCH_USER", - id: "11795c64-40ea-4198-b06e-3c873ed9039d", - }, - - noSuchGroup: { - message: "No such group.", - code: "NO_SUCH_GROUP", - id: "c94e2a5d-06aa-4914-8fa6-6a42e73d6537", - }, - - groupAccessDenied: { - message: "You can not send messages to groups that you have not joined.", - code: "GROUP_ACCESS_DENIED", - id: "d96b3cca-5ad1-438b-ad8b-02f931308fbd", - }, - - noSuchFile: { - message: "No such file.", - code: "NO_SUCH_FILE", - id: "4372b8e2-185d-4146-8749-2f68864a3e5f", - }, - - contentRequired: { - message: "Content required. You need to set text or fileId.", - code: "CONTENT_REQUIRED", - id: "25587321-b0e6-449c-9239-f8925092942c", - }, - - youHaveBeenBlocked: { - message: - "You cannot send a message because you have been blocked by this user.", - code: "YOU_HAVE_BEEN_BLOCKED", - id: "c15a5199-7422-4968-941a-2a462c478f7d", - }, - }, -} as const; - -export const paramDef = { - type: "object", - properties: { - text: { type: "string", nullable: true, maxLength: 3000 }, - fileId: { type: "string", format: "misskey:id" }, - }, - anyOf: [ - { - properties: { - userId: { type: "string", format: "misskey:id" }, - }, - required: ["userId"], - }, - { - properties: { - groupId: { type: "string", format: "misskey:id" }, - }, - required: ["groupId"], - }, - ], -} as const; - -export default define(meta, paramDef, async (ps, user) => { - let recipientUser: User | null; - let recipientGroup: UserGroup | null; - - if (ps.userId != null) { - // Myself - if (ps.userId === user.id) { - throw new ApiError(meta.errors.recipientIsYourself); - } - - // Fetch recipient (user) - recipientUser = await getUser(ps.userId).catch((e) => { - if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") - throw new ApiError(meta.errors.noSuchUser); - throw e; - }); - - // Check blocking - const block = await Blockings.findOneBy({ - blockerId: recipientUser.id, - blockeeId: user.id, - }); - if (block) { - throw new ApiError(meta.errors.youHaveBeenBlocked); - } - } else if (ps.groupId != null) { - // Fetch recipient (group) - recipientGroup = await UserGroups.findOneBy({ id: ps.groupId! }); - - if (recipientGroup == null) { - throw new ApiError(meta.errors.noSuchGroup); - } - - // check joined - const joining = await UserGroupJoinings.findOneBy({ - userId: user.id, - userGroupId: recipientGroup.id, - }); - - if (joining == null) { - throw new ApiError(meta.errors.groupAccessDenied); - } - } - - let file = null; - if (ps.fileId != null) { - file = await DriveFiles.findOneBy({ - id: ps.fileId, - userId: user.id, - }); - - if (file == null) { - throw new ApiError(meta.errors.noSuchFile); - } - } - - // テキストが無いかつ添付ファイルも無かったらエラー - if (ps.text == null && file == null) { - throw new ApiError(meta.errors.contentRequired); - } - - return await createMessage( - user, - recipientUser, - recipientGroup, - ps.text, - file, - ); -}); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts b/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts deleted file mode 100644 index 42ff050d16..0000000000 --- a/packages/backend/src/server/api/endpoints/messaging/messages/delete.ts +++ /dev/null @@ -1,48 +0,0 @@ -import define from "../../../define.js"; -import { ApiError } from "../../../error.js"; -import { MessagingMessages } from "@/models/index.js"; -import { deleteMessage } from "@/services/messages/delete.js"; -import { SECOND, HOUR } from "@/const.js"; - -export const meta = { - tags: ["messaging"], - - requireCredential: true, - - kind: "write:messaging", - - limit: { - duration: HOUR, - max: 300, - minInterval: SECOND, - }, - - errors: { - noSuchMessage: { - message: "No such message.", - code: "NO_SUCH_MESSAGE", - id: "54b5b326-7925-42cf-8019-130fda8b56af", - }, - }, -} as const; - -export const paramDef = { - type: "object", - properties: { - messageId: { type: "string", format: "misskey:id" }, - }, - required: ["messageId"], -} as const; - -export default define(meta, paramDef, async (ps, user) => { - const message = await MessagingMessages.findOneBy({ - id: ps.messageId, - userId: user.id, - }); - - if (message == null) { - throw new ApiError(meta.errors.noSuchMessage); - } - - await deleteMessage(message); -}); diff --git a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts b/packages/backend/src/server/api/endpoints/messaging/messages/read.ts deleted file mode 100644 index 0ef013b799..0000000000 --- a/packages/backend/src/server/api/endpoints/messaging/messages/read.ts +++ /dev/null @@ -1,57 +0,0 @@ -import define from "../../../define.js"; -import { ApiError } from "../../../error.js"; -import { MessagingMessages } from "@/models/index.js"; -import { - readUserMessagingMessage, - readGroupMessagingMessage, -} from "../../../common/read-messaging-message.js"; - -export const meta = { - tags: ["messaging"], - - requireCredential: true, - - kind: "write:messaging", - - errors: { - noSuchMessage: { - message: "No such message.", - code: "NO_SUCH_MESSAGE", - id: "86d56a2f-a9c3-4afb-b13c-3e9bfef9aa14", - }, - }, -} as const; - -export const paramDef = { - type: "object", - properties: { - messageId: { type: "string", format: "misskey:id" }, - }, - required: ["messageId"], -} as const; - -export default define(meta, paramDef, async (ps, user) => { - const message = await MessagingMessages.findOneBy({ id: ps.messageId }); - - if (message == null) { - throw new ApiError(meta.errors.noSuchMessage); - } - - if (message.recipientId) { - await readUserMessagingMessage(user.id, message.userId, [message.id]).catch( - (e) => { - if (e.id === "e140a4bf-49ce-4fb6-b67c-b78dadf6b52f") - throw new ApiError(meta.errors.noSuchMessage); - throw e; - }, - ); - } else if (message.groupId) { - await readGroupMessagingMessage(user.id, message.groupId, [ - message.id, - ]).catch((e) => { - if (e.id === "930a270c-714a-46b2-b776-ad27276dc569") - throw new ApiError(meta.errors.noSuchMessage); - throw e; - }); - } -}); diff --git a/packages/backend/src/server/api/index.ts b/packages/backend/src/server/api/index.ts index da98a9df19..b84bbdbb39 100644 --- a/packages/backend/src/server/api/index.ts +++ b/packages/backend/src/server/api/index.ts @@ -7,7 +7,6 @@ import Router from "@koa/router"; import multer from "@koa/multer"; import bodyParser from "koa-bodyparser"; import cors from "@koa/cors"; -import { apiMastodonCompatible } from './mastodon/ApiMastodonCompatibleService.js'; import { Instances, AccessTokens, Users } from "@/models/index.js"; import config from "@/config/index.js"; import endpoints from "./endpoints.js"; @@ -58,8 +57,6 @@ const upload = multer({ // Init router const router = new Router(); -apiMastodonCompatible(router); - /** * Register endpoint handlers */ diff --git a/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts b/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts deleted file mode 100644 index 57a86c96d2..0000000000 --- a/packages/backend/src/server/api/mastodon/ApiMastodonCompatibleService.ts +++ /dev/null @@ -1,58 +0,0 @@ -import Router from "@koa/router"; -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; -import { apiAuthMastodon } from './endpoints/auth.js'; -import { apiAccountMastodon } from './endpoints/account.js'; -import { apiStatusMastodon } from './endpoints/status.js'; -import { apiFilterMastodon } from './endpoints/filter.js'; -import { apiTimelineMastodon } from './endpoints/timeline.js'; -import { apiNotificationsMastodon } from './endpoints/notifications.js'; -import { apiSearchMastodon } from './endpoints/search.js'; -import { getInstance } from './endpoints/meta.js'; - -export function getClient(BASE_URL: string, authorization: string | undefined): MegalodonInterface { - const accessTokenArr = authorization?.split(' ') ?? [null]; - const accessToken = accessTokenArr[accessTokenArr.length - 1]; - const generator = (megalodon as any).default - const client = generator('misskey', BASE_URL, accessToken) as MegalodonInterface; - return client -} - -export function apiMastodonCompatible(router: Router): void { - apiAuthMastodon(router) - apiAccountMastodon(router) - apiStatusMastodon(router) - apiFilterMastodon(router) - apiTimelineMastodon(router) - apiNotificationsMastodon(router) - apiSearchMastodon(router) - - router.get('/v1/custom_emojis', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getInstanceCustomEmojis(); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.get('/v1/instance', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); // we are using this here, because in private mode some info isnt - // displayed without being logged in - try { - const data = await client.getInstance(); - ctx.body = getInstance(data.data); - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/account.ts b/packages/backend/src/server/api/mastodon/endpoints/account.ts deleted file mode 100644 index 61d4da8a8a..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/account.ts +++ /dev/null @@ -1,323 +0,0 @@ -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; -import Router from "@koa/router"; -import { koaBody } from 'koa-body'; -import { getClient } from '../ApiMastodonCompatibleService.js'; -import { toLimitToInt } from './timeline.js'; - -export function apiAccountMastodon(router: Router): void { - - router.get('/v1/accounts/verify_credentials', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.verifyAccountCredentials(); - const acct = data.data; - acct.url = `${BASE_URL}/@${acct.url}` - acct.note = '' - acct.avatar_static = acct.avatar - acct.header = acct.header || '' - acct.header_static = acct.header || '' - acct.source = { - note: acct.note, - fields: acct.fields, - privacy: 'public', - sensitive: false, - language: '' - } - ctx.body = acct - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.patch('/v1/accounts/update_credentials', async (ctx) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.updateCredentials((ctx.request as any).body as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/accounts/:id', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getAccount(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/accounts/:id/statuses', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getAccountStatuses(ctx.params.id, toLimitToInt(ctx.query as any)); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/accounts/:id/followers', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getAccountFollowers(ctx.params.id, ctx.query as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/accounts/:id/following', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getAccountFollowing(ctx.params.id, ctx.query as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/accounts/:id/lists', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getAccountLists(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/accounts/:id/follow', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.followAccount(ctx.params.id); - const acct = data.data; - acct.following = true; - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/accounts/:id/unfollow', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.unfollowAccount(ctx.params.id); - const acct = data.data; - acct.following = false; - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/accounts/:id/block', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.blockAccount(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/accounts/:id/unblock', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.unblockAccount(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/accounts/:id/mute', async (ctx) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.muteAccount(ctx.params.id, (ctx.request as any).body as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/accounts/:id/unmute', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.unmuteAccount(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get('/v1/accounts/relationships', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const idsRaw = (ctx.query as any)['id[]'] - const ids = typeof idsRaw === 'string' ? [idsRaw] : idsRaw - const data = await client.getRelationships(ids) as any; - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get('/v1/bookmarks', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getBookmarks(ctx.query as any) as any; - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get('/v1/favourites', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getFavourites(ctx.query as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get('/v1/mutes', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getMutes(ctx.query as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get('/v1/blocks', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getBlocks(ctx.query as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.get('/v1/follow_ctxs', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getFollowRequests((ctx.query as any || { limit: 20 }).limit); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/follow_ctxs/:id/authorize', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.acceptFollowRequest(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/follow_ctxs/:id/reject', async (ctx, next) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.rejectFollowRequest(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status =(401); - ctx.body = e.response.data; - } - }); - -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/auth.ts b/packages/backend/src/server/api/mastodon/endpoints/auth.ts deleted file mode 100644 index ff8b8a5188..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/auth.ts +++ /dev/null @@ -1,81 +0,0 @@ -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; -import Router from "@koa/router"; -import { koaBody } from 'koa-body'; -import { getClient } from '../ApiMastodonCompatibleService.js'; - -const readScope = [ - 'read:account', - 'read:drive', - 'read:blocks', - 'read:favorites', - 'read:following', - 'read:messaging', - 'read:mutes', - 'read:notifications', - 'read:reactions', - 'read:pages', - 'read:page-likes', - 'read:user-groups', - 'read:channels', - 'read:gallery', - 'read:gallery-likes' -] -const writeScope = [ - 'write:account', - 'write:drive', - 'write:blocks', - 'write:favorites', - 'write:following', - 'write:messaging', - 'write:mutes', - 'write:notes', - 'write:notifications', - 'write:reactions', - 'write:votes', - 'write:pages', - 'write:page-likes', - 'write:user-groups', - 'write:channels', - 'write:gallery', - 'write:gallery-likes' -] - -export function apiAuthMastodon(router: Router): void { - - router.post('/v1/apps', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - let scope = body.scopes - console.log(body) - if (typeof scope === 'string') scope = scope.split(' ') - const pushScope = new Set() - for (const s of scope) { - if (s.match(/^read/)) for (const r of readScope) pushScope.add(r) - if (s.match(/^write/)) for (const r of writeScope) pushScope.add(r) - } - const scopeArr = Array.from(pushScope) - - let red = body.redirect_uris - if (red === 'urn:ietf:wg:oauth:2.0:oob') { - red = 'https://thedesk.top/hello.html' - } - const appData = await client.registerApp(body.client_name, { scopes: scopeArr, redirect_uris: red, website: body.website }); - ctx.body = { - id: appData.id, - name: appData.name, - website: appData.website, - redirect_uri: red, - client_id: Buffer.from(appData.url || '').toString('base64'), - client_secret: appData.clientSecret, - } - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/filter.ts b/packages/backend/src/server/api/mastodon/endpoints/filter.ts deleted file mode 100644 index 810b8be110..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/filter.ts +++ /dev/null @@ -1,83 +0,0 @@ -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; -import Router from "@koa/router"; -import { koaBody } from 'koa-body'; -import { getClient } from '../ApiMastodonCompatibleService.js'; - -export function apiFilterMastodon(router: Router): void { - - router.get('/v1/filters', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.getFilters(); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.get('/v1/filters/:id', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.getFilter(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.post('/v1/filters', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.createFilter(body.phrase, body.context, body); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.post('/v1/filters/:id', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.updateFilter(ctx.params.id, body.phrase, body.context); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.delete('/v1/filters/:id', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.deleteFilter(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/meta.ts b/packages/backend/src/server/api/mastodon/endpoints/meta.ts deleted file mode 100644 index 3496272b9e..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/meta.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Entity } from "@cutls/megalodon"; -// TODO: add calckey features -export function getInstance(response: Entity.Instance) { - return { - uri: response.uri, - title: response.title || "", - short_description: response.description || "", - description: response.description || "", - email: response.email || "", - version: "3.0.0 compatible (Calckey)", - urls: response.urls, - stats: response.stats, - thumbnail: response.thumbnail || "", - languages: ["en", "de", "ja"], - registrations: response.registrations, - approval_required: !response.registrations, - invites_enabled: response.registrations, - configuration: { - accounts: { - max_featured_tags: 20, - }, - statuses: { - max_characters: 3000, - max_media_attachments: 4, - characters_reserved_per_url: response.uri.length, - }, - media_attachments: { - supported_mime_types: [ - "image/jpeg", - "image/png", - "image/gif", - "image/heic", - "image/heif", - "image/webp", - "image/avif", - "video/webm", - "video/mp4", - "video/quicktime", - "video/ogg", - "audio/wave", - "audio/wav", - "audio/x-wav", - "audio/x-pn-wave", - "audio/vnd.wave", - "audio/ogg", - "audio/vorbis", - "audio/mpeg", - "audio/mp3", - "audio/webm", - "audio/flac", - "audio/aac", - "audio/m4a", - "audio/x-m4a", - "audio/mp4", - "audio/3gpp", - "video/x-ms-asf", - ], - image_size_limit: 10485760, - image_matrix_limit: 16777216, - video_size_limit: 41943040, - video_frame_rate_limit: 60, - video_matrix_limit: 2304000, - }, - polls: { - max_options: 8, - max_characters_per_option: 50, - min_expiration: 300, - max_expiration: 2629746, - }, - }, - contact_account: { - id: "1", - username: "admin", - acct: "admin", - display_name: "admin", - locked: true, - bot: true, - discoverable: false, - group: false, - created_at: "1971-01-01T00:00:00.000Z", - note: "", - url: "https://http.cat/404", - avatar: "https://http.cat/404", - avatar_static: "https://http.cat/404", - header: "https://http.cat/404", - header_static: "https://http.cat/404", - followers_count: -1, - following_count: 0, - statuses_count: 0, - last_status_at: "1971-01-01T00:00:00.000Z", - noindex: true, - emojis: [], - fields: [], - }, - rules: [], - }; -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts b/packages/backend/src/server/api/mastodon/endpoints/notifications.ts deleted file mode 100644 index 625ff386c1..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/notifications.ts +++ /dev/null @@ -1,89 +0,0 @@ -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; -import Router from "@koa/router"; -import { koaBody } from 'koa-body'; -import { getClient } from '../ApiMastodonCompatibleService.js'; -import { toTextWithReaction } from './timeline.js'; -function toLimitToInt(q: any) { - if (q.limit) if (typeof q.limit === 'string') q.limit = parseInt(q.limit, 10) - return q -} - -export function apiNotificationsMastodon(router: Router): void { - - router.get('/v1/notifications', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.getNotifications(toLimitToInt(ctx.query)); - const notfs = data.data; - const ret = notfs.map((n) => { - if(n.type !== 'follow' && n.type !== 'follow_request') { - if (n.type === 'reaction') n.type = 'favourite' - n.status = toTextWithReaction(n.status ? [n.status] : [], ctx.hostname)[0] - return n - } else { - return n - } - }) - ctx.body = ret; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.get('/v1/notification/:id', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const dataRaw = await client.getNotification(ctx.params.id); - const data = dataRaw.data; - if(data.type !== 'follow' && data.type !== 'follow_request') { - if (data.type === 'reaction') data.type = 'favourite' - ctx.body = toTextWithReaction([data as any], ctx.request.hostname)[0] - } else { - ctx.body = data - } - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.post('/v1/notifications/clear', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.dismissNotifications(); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - - router.post('/v1/notification/:id/dismiss', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const data = await client.dismissNotification(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/search.ts b/packages/backend/src/server/api/mastodon/endpoints/search.ts deleted file mode 100644 index dce3ff57c8..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/search.ts +++ /dev/null @@ -1,25 +0,0 @@ -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; -import Router from "@koa/router"; -import { koaBody } from 'koa-body'; -import { getClient } from '../ApiMastodonCompatibleService.js'; - -export function apiSearchMastodon(router: Router): void { - - router.get('/v1/search', async (ctx) => { - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const accessTokens = ctx.request.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const body: any = ctx.request.body; - try { - const query: any = ctx.query - const type = query.type || '' - const data = await client.search(query.q, type, query); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = 401; - ctx.body = e.response.data; - } - }); - -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts deleted file mode 100644 index 8dc4ba5f7d..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ /dev/null @@ -1,403 +0,0 @@ -import Router from "@koa/router"; -import { koaBody } from 'koa-body'; -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; -import { getClient } from '../ApiMastodonCompatibleService.js'; -import fs from 'fs' -import { pipeline } from 'node:stream'; -import { promisify } from 'node:util'; -import { createTemp } from '@/misc/create-temp.js'; -import { emojiRegex, emojiRegexAtStartToEnd } from '@/misc/emoji-regex.js'; -import axios from 'axios'; -const pump = promisify(pipeline); - -export function apiStatusMastodon(router: Router): void { - router.post('/v1/statuses', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const body: any = ctx.request.body - const text = body.status - const removed = text.replace(/@\S+/g, '').replaceAll(' ', '') - const isDefaultEmoji = emojiRegexAtStartToEnd.test(removed) - const isCustomEmoji = /^:[a-zA-Z0-9@_]+:$/.test(removed) - if (body.in_reply_to_id && isDefaultEmoji || isCustomEmoji) { - const a = await client.createEmojiReaction(body.in_reply_to_id, removed) - ctx.body = a.data - } - if (body.in_reply_to_id && removed === '/unreact') { - try { - const id = body.in_reply_to_id - const post = await client.getStatus(id) - const react = post.data.emoji_reactions.filter((e) => e.me)[0].name - const data = await client.deleteEmojiReaction(id, react); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - } - if (!body.media_ids) body.media_ids = undefined - if (body.media_ids && !body.media_ids.length) body.media_ids = undefined - const data = await client.postStatus(text, body); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/statuses/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getStatus(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.delete<{ Params: { id: string } }>('/v1/statuses/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.deleteStatus(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - interface IReaction { - id: string - createdAt: string - user: MisskeyEntity.User, - type: string - } - router.get<{ Params: { id: string } }>('/v1/statuses/:id/context', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const id = ctx.params.id - const data = await client.getStatusContext(id, ctx.query as any); - const status = await client.getStatus(id); - const reactionsAxios = await axios.get(`${BASE_URL}/api/notes/reactions?noteId=${id}`) - const reactions: IReaction[] = reactionsAxios.data - const text = reactions.map((r) => `${r.type.replace('@.', '')} ${r.user.username}`).join('
') - data.data.descendants.unshift(statusModel(status.data.id, status.data.account.id, status.data.emojis, text)) - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/statuses/:id/reblogged_by', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getStatusRebloggedBy(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/statuses/:id/favourited_by', async (ctx, reply) => { - ctx.body = [] - }); - router.post<{ Params: { id: string } }>('/v1/statuses/:id/favourite', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const react = await getFirstReaction(BASE_URL, accessTokens); - try { - const a = await client.createEmojiReaction(ctx.params.id, react) as any; - //const data = await client.favouriteStatus(ctx.params.id) as any; - ctx.body = a.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/statuses/:id/unfavourite', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - const react = await getFirstReaction(BASE_URL, accessTokens); - try { - const data = await client.deleteEmojiReaction(ctx.params.id, react); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - - router.post<{ Params: { id: string } }>('/v1/statuses/:id/reblog', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.reblogStatus(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - - router.post<{ Params: { id: string } }>('/v1/statuses/:id/unreblog', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.unreblogStatus(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - - router.post<{ Params: { id: string } }>('/v1/statuses/:id/bookmark', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.bookmarkStatus(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - - router.post<{ Params: { id: string } }>('/v1/statuses/:id/unbookmark', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.unbookmarkStatus(ctx.params.id) as any; - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - - router.post<{ Params: { id: string } }>('/v1/statuses/:id/pin', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.pinStatus(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - - router.post<{ Params: { id: string } }>('/v1/statuses/:id/unpin', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.unpinStatus(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.post('/v1/media', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const multipartData = await ctx.file; - if (!multipartData) { - ctx.body = { error: 'No image' }; - return; - } - const [path] = await createTemp(); - await pump(multipartData.buffer, fs.createWriteStream(path)); - const image = fs.readFileSync(path); - const data = await client.uploadMedia(image); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.post('/v2/media', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const multipartData = await ctx.file; - if (!multipartData) { - ctx.body = { error: 'No image' }; - return; - } - const [path] = await createTemp(); - await pump(multipartData.buffer, fs.createWriteStream(path)); - const image = fs.readFileSync(path); - const data = await client.uploadMedia(image); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/media/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getMedia(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.put<{ Params: { id: string } }>('/v1/media/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.updateMedia(ctx.params.id, ctx.request.body as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/polls/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getPoll(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/polls/:id/votes', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.votePoll(ctx.params.id, (ctx.request.body as any).choices); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - -} - -async function getFirstReaction(BASE_URL: string, accessTokens: string | undefined) { - const accessTokenArr = accessTokens?.split(' ') ?? [null]; - const accessToken = accessTokenArr[accessTokenArr.length - 1]; - let react = '👍' - try { - const api = await axios.post(`${BASE_URL}/api/i/registry/get-unsecure`, { - scope: ['client', 'base'], - key: 'reactions', - i: accessToken - }) - const reactRaw = api.data - react = Array.isArray(reactRaw) ? api.data[0] : '👍' - console.log(api.data) - return react - } catch (e) { - return react - } -} - -export function statusModel(id: string | null, acctId: string | null, emojis: MastodonEntity.Emoji[], content: string) { - const now = "1970-01-02T00:00:00.000Z" - return { - id: '9atm5frjhb', - uri: 'https://http.cat/404', // "" - url: 'https://http.cat/404', // "", - account: { - id: '9arzuvv0sw', - username: 'ReactionBot', - acct: 'ReactionBot', - display_name: 'ReactionOfThisPost', - locked: false, - created_at: now, - followers_count: 0, - following_count: 0, - statuses_count: 0, - note: '', - url: 'https://http.cat/404', - avatar: 'https://http.cat/404', - avatar_static: 'https://http.cat/404', - header: 'https://http.cat/404', // "" - header_static: 'https://http.cat/404', // "" - emojis: [], - fields: [], - moved: null, - bot: false, - }, - in_reply_to_id: id, - in_reply_to_account_id: acctId, - reblog: null, - content: `

${content}

`, - plain_content: null, - created_at: now, - emojis: emojis, - replies_count: 0, - reblogs_count: 0, - favourites_count: 0, - favourited: false, - reblogged: false, - muted: false, - sensitive: false, - spoiler_text: '', - visibility: 'public' as const, - media_attachments: [], - mentions: [], - tags: [], - card: null, - poll: null, - application: null, - language: null, - pinned: false, - emoji_reactions: [], - bookmarked: false, - quote: false, - } -} diff --git a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts b/packages/backend/src/server/api/mastodon/endpoints/timeline.ts deleted file mode 100644 index 3fdb6ce881..0000000000 --- a/packages/backend/src/server/api/mastodon/endpoints/timeline.ts +++ /dev/null @@ -1,246 +0,0 @@ -import Router from "@koa/router"; -import { koaBody } from 'koa-body'; -import megalodon, { Entity, MegalodonInterface } from '@cutls/megalodon'; -import { getClient } from '../ApiMastodonCompatibleService.js' -import { statusModel } from './status.js'; -import Autolinker from 'autolinker'; -import { ParsedUrlQuery } from "querystring"; - -export function toLimitToInt(q: ParsedUrlQuery) { - if (q.limit) if (typeof q.limit === 'string') q.limit = parseInt(q.limit, 10).toString() - return q -} - -export function toTextWithReaction(status: Entity.Status[], host: string) { - return status.map((t) => { - if (!t) return statusModel(null, null, [], 'no content') - if (!t.emoji_reactions) return t - if (t.reblog) t.reblog = toTextWithReaction([t.reblog], host)[0] - const reactions = t.emoji_reactions.map((r) => `${r.name.replace('@.', '')} (${r.count}${r.me ? "* " : ''})`); - //t.emojis = getEmoji(t.content, host) - t.content = `

${autoLinker(t.content, host)}

${reactions.join(', ')}

` - return t - }) -} -export function autoLinker(input: string, host: string) { - return Autolinker.link(input, { - hashtag: 'twitter', - mention: 'twitter', - email: false, - stripPrefix: false, - replaceFn : function (match) { - switch(match.type) { - case 'url': - return true - case 'mention': - console.log("Mention: ", match.getMention()); - console.log("Mention Service Name: ", match.getServiceName()); - return `@${match.getMention()}`; - case 'hashtag': - console.log("Hashtag: ", match.getHashtag()); - return `#${match.getHashtag()}`; - } - return false - } - } ); -} - -export function apiTimelineMastodon(router: Router): void { - router.get('/v1/timelines/public', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const query: any = ctx.query - const data = query.local ? await client.getLocalTimeline(toLimitToInt(query)) : await client.getPublicTimeline(toLimitToInt(query)); - ctx.body = toTextWithReaction(data.data, ctx.hostname); - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { hashtag: string } }>('/v1/timelines/tag/:hashtag', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getTagTimeline(ctx.params.hashtag, toLimitToInt(ctx.query)); - ctx.body = toTextWithReaction(data.data, ctx.hostname); - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { hashtag: string } }>('/v1/timelines/home', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getHomeTimeline(toLimitToInt(ctx.query)); - ctx.body = toTextWithReaction(data.data, ctx.hostname); - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { listId: string } }>('/v1/timelines/list/:listId', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getListTimeline(ctx.params.listId, toLimitToInt(ctx.query)); - ctx.body = toTextWithReaction(data.data, ctx.hostname); - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get('/v1/conversations', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getConversationTimeline(toLimitToInt(ctx.query)); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get('/v1/lists', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getLists(); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/lists/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getList(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.post('/v1/lists', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.createList((ctx.query as any).title); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.put<{ Params: { id: string } }>('/v1/lists/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.updateList(ctx.params.id, ctx.query as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.delete<{ Params: { id: string } }>('/v1/lists/:id', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.deleteList(ctx.params.id); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.get<{ Params: { id: string } }>('/v1/lists/:id/accounts', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.getAccountsInList(ctx.params.id, ctx.query as any); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.post<{ Params: { id: string } }>('/v1/lists/:id/accounts', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.addAccountsToList(ctx.params.id, (ctx.query as any).account_ids); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); - router.delete<{ Params: { id: string } }>('/v1/lists/:id/accounts', async (ctx, reply) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); - try { - const data = await client.deleteAccountsFromList(ctx.params.id, (ctx.query as any).account_ids); - ctx.body = data.data; - } catch (e: any) { - console.error(e) - console.error(e.response.data) - ctx.status = (401); - ctx.body = e.response.data; - } - }); -} -function escapeHTML(str: string) { - if (!str) { - return '' - } - return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''') -} -function nl2br(str: string) { - if (!str) { - return '' - } - str = str.replace(/\r\n/g, '
') - str = str.replace(/(\n|\r)/g, '
') - return str -} diff --git a/packages/backend/src/server/api/stream/channels/index.ts b/packages/backend/src/server/api/stream/channels/index.ts index d1127be47c..2213fc119d 100644 --- a/packages/backend/src/server/api/stream/channels/index.ts +++ b/packages/backend/src/server/api/stream/channels/index.ts @@ -8,8 +8,6 @@ import serverStats from "./server-stats.js"; import queueStats from "./queue-stats.js"; import userList from "./user-list.js"; import antenna from "./antenna.js"; -import messaging from "./messaging.js"; -import messagingIndex from "./messaging-index.js"; import drive from "./drive.js"; import hashtag from "./hashtag.js"; import channel from "./channel.js"; @@ -26,8 +24,6 @@ export default { queueStats, userList, antenna, - messaging, - messagingIndex, drive, hashtag, channel, diff --git a/packages/backend/src/server/api/stream/channels/messaging-index.ts b/packages/backend/src/server/api/stream/channels/messaging-index.ts deleted file mode 100644 index 8165172d73..0000000000 --- a/packages/backend/src/server/api/stream/channels/messaging-index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import Channel from "../channel.js"; - -export default class extends Channel { - public readonly chName = "messagingIndex"; - public static shouldShare = true; - public static requireCredential = true; - - public async init(params: any) { - // Subscribe messaging index stream - this.subscriber.on(`messagingIndexStream:${this.user!.id}`, (data) => { - this.send(data); - }); - } -} diff --git a/packages/backend/src/server/api/stream/channels/messaging.ts b/packages/backend/src/server/api/stream/channels/messaging.ts deleted file mode 100644 index dc18250592..0000000000 --- a/packages/backend/src/server/api/stream/channels/messaging.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { - readUserMessagingMessage, - readGroupMessagingMessage, - deliverReadActivity, -} from "../../common/read-messaging-message.js"; -import Channel from "../channel.js"; -import { UserGroupJoinings, Users, MessagingMessages } from "@/models/index.js"; -import type { User, ILocalUser, IRemoteUser } from "@/models/entities/user.js"; -import type { UserGroup } from "@/models/entities/user-group.js"; -import type { StreamMessages } from "../types.js"; - -export default class extends Channel { - public readonly chName = "messaging"; - public static shouldShare = false; - public static requireCredential = true; - - private otherpartyId: string | null; - private otherparty: User | null; - private groupId: string | null; - private subCh: - | `messagingStream:${User["id"]}-${User["id"]}` - | `messagingStream:${UserGroup["id"]}`; - private typers: Record = {}; - private emitTypersIntervalId: ReturnType; - - constructor(id: string, connection: Channel["connection"]) { - super(id, connection); - this.onEvent = this.onEvent.bind(this); - this.onMessage = this.onMessage.bind(this); - this.emitTypers = this.emitTypers.bind(this); - } - - public async init(params: any) { - this.otherpartyId = params.otherparty; - this.otherparty = this.otherpartyId - ? await Users.findOneByOrFail({ id: this.otherpartyId }) - : null; - this.groupId = params.group; - - // Check joining - if (this.groupId) { - const joining = await UserGroupJoinings.findOneBy({ - userId: this.user!.id, - userGroupId: this.groupId, - }); - - if (joining == null) { - return; - } - } - - this.emitTypersIntervalId = setInterval(this.emitTypers, 5000); - - this.subCh = this.otherpartyId - ? `messagingStream:${this.user!.id}-${this.otherpartyId}` - : `messagingStream:${this.groupId}`; - - // Subscribe messaging stream - this.subscriber.on(this.subCh, this.onEvent); - } - - private onEvent( - data: - | StreamMessages["messaging"]["payload"] - | StreamMessages["groupMessaging"]["payload"], - ) { - if (data.type === "typing") { - const id = data.body; - const begin = this.typers[id] == null; - this.typers[id] = new Date(); - if (begin) { - this.emitTypers(); - } - } else { - this.send(data); - } - } - - public onMessage(type: string, body: any) { - switch (type) { - case "read": - if (this.otherpartyId) { - readUserMessagingMessage(this.user!.id, this.otherpartyId, [body.id]); - - // リモートユーザーからのメッセージだったら既読配信 - if ( - Users.isLocalUser(this.user!) && - Users.isRemoteUser(this.otherparty!) - ) { - MessagingMessages.findOneBy({ id: body.id }).then((message) => { - if (message) - deliverReadActivity( - this.user as ILocalUser, - this.otherparty as IRemoteUser, - message, - ); - }); - } - } else if (this.groupId) { - readGroupMessagingMessage(this.user!.id, this.groupId, [body.id]); - } - break; - } - } - - private async emitTypers() { - const now = new Date(); - - // Remove not typing users - for (const [userId, date] of Object.entries(this.typers)) { - if (now.getTime() - date.getTime() > 5000) - this.typers[userId] = undefined; - } - - const users = await Users.packMany(Object.keys(this.typers), null, { - detail: false, - }); - - this.send({ - type: "typers", - body: users, - }); - } - - public dispose() { - this.subscriber.off(this.subCh, this.onEvent); - - clearInterval(this.emitTypersIntervalId); - } -} diff --git a/packages/backend/src/server/api/stream/index.ts b/packages/backend/src/server/api/stream/index.ts index 5be8ab109e..099e528abf 100644 --- a/packages/backend/src/server/api/stream/index.ts +++ b/packages/backend/src/server/api/stream/index.ts @@ -4,7 +4,6 @@ import readNote from "@/services/note/read.js"; import type { User } from "@/models/entities/user.js"; import type { Channel as ChannelModel } from "@/models/entities/channel.js"; import { - Users, Followings, Mutings, UserProfiles, @@ -13,20 +12,12 @@ import { } from "@/models/index.js"; import type { AccessToken } from "@/models/entities/access-token.js"; import type { UserProfile } from "@/models/entities/user-profile.js"; -import { - publishChannelStream, - publishGroupMessagingStream, - publishMessagingStream, -} from "@/services/stream.js"; import type { UserGroup } from "@/models/entities/user-group.js"; import type { Packed } from "@/misc/schema.js"; import { readNotification } from "../common/read-notification.js"; import channels from "./channels/index.js"; import type Channel from "./channel.js"; import type { StreamEventEmitter, StreamMessages } from "./types.js"; -import { Converter } from "@cutls/megalodon"; -import { getClient } from "../mastodon/ApiMastodonCompatibleService.js"; -import { toTextWithReaction } from "../mastodon/endpoints/timeline.js"; /** * Main stream connection @@ -44,27 +35,17 @@ export default class Connection { private channels: Channel[] = []; private subscribingNotes: any = {}; private cachedNotes: Packed<"Note">[] = []; - private isMastodonCompatible: boolean = false; - private host: string; - private accessToken: string; - private currentSubscribe: string[][] = []; constructor( wsConnection: websocket.connection, subscriber: EventEmitter, user: User | null | undefined, token: AccessToken | null | undefined, - host: string, - accessToken: string, - prepareStream: string | undefined, ) { - console.log("constructor", prepareStream); this.wsConnection = wsConnection; this.subscriber = subscriber; if (user) this.user = user; if (token) this.token = token; - if (host) this.host = host; - if (accessToken) this.accessToken = accessToken; this.onWsConnectionMessage = this.onWsConnectionMessage.bind(this); this.onUserEvent = this.onUserEvent.bind(this); @@ -86,13 +67,6 @@ export default class Connection { this.subscriber.on(`user:${this.user.id}`, this.onUserEvent); } - console.log("prepare", prepareStream); - if (prepareStream) { - this.onWsConnectionMessage({ - type: "utf8", - utf8Data: JSON.stringify({ stream: prepareStream, type: "subscribe" }), - }); - } } private onUserEvent(data: StreamMessages["user"]["payload"]) { @@ -145,149 +119,49 @@ export default class Connection { if (data.type !== "utf8") return; if (data.utf8Data == null) return; - let objs: Record[]; + let obj: Record; try { - objs = [JSON.parse(data.utf8Data)]; + obj = JSON.parse(data.utf8Data); } catch (e) { return; } - - const simpleObj = objs[0]; - if (simpleObj.stream) { - // is Mastodon Compatible - this.isMastodonCompatible = true; - if (simpleObj.type === "subscribe") { - let forSubscribe = []; - if (simpleObj.stream === "user") { - this.currentSubscribe.push(["user"]); - objs = [ - { - type: "connect", - body: { - channel: "main", - id: simpleObj.stream, - }, - }, - { - type: "connect", - body: { - channel: "homeTimeline", - id: simpleObj.stream, - }, - }, - ]; - const client = getClient(this.host, this.accessToken); - try { - const tl = await client.getHomeTimeline(); - for (const t of tl.data) forSubscribe.push(t.id); - } catch (e: any) { - console.log(e); - console.error(e.response.data); - } - } else if (simpleObj.stream === "public:local") { - this.currentSubscribe.push(["public:local"]); - objs = [ - { - type: "connect", - body: { - channel: "localTimeline", - id: simpleObj.stream, - }, - }, - ]; - const client = getClient(this.host, this.accessToken); - const tl = await client.getLocalTimeline(); - for (const t of tl.data) forSubscribe.push(t.id); - } else if (simpleObj.stream === "public") { - this.currentSubscribe.push(["public"]); - objs = [ - { - type: "connect", - body: { - channel: "globalTimeline", - id: simpleObj.stream, - }, - }, - ]; - const client = getClient(this.host, this.accessToken); - const tl = await client.getPublicTimeline(); - for (const t of tl.data) forSubscribe.push(t.id); - } else if (simpleObj.stream === "list") { - this.currentSubscribe.push(["list", simpleObj.list]); - objs = [ - { - type: "connect", - body: { - channel: "list", - id: simpleObj.stream, - params: { - listId: simpleObj.list, - }, - }, - }, - ]; - const client = getClient(this.host, this.accessToken); - const tl = await client.getListTimeline(simpleObj.list); - for (const t of tl.data) forSubscribe.push(t.id); - } - for (const s of forSubscribe) { - objs.push({ - type: "s", - body: { - id: s, - }, - }); - } - } - } - for (const obj of objs) { - const { type, body } = obj; - console.log(type, body); - switch (type) { - case "readNotification": - this.onReadNotification(body); - break; - case "subNote": - this.onSubscribeNote(body); - break; - case "s": - this.onSubscribeNote(body); - break; // alias - case "sr": - this.onSubscribeNote(body); - this.readNote(body); - break; - case "unsubNote": - this.onUnsubscribeNote(body); - break; - case "un": - this.onUnsubscribeNote(body); - break; // alias - case "connect": - this.onChannelConnectRequested(body); - break; - case "disconnect": - this.onChannelDisconnectRequested(body); - break; - case "channel": - this.onChannelMessageRequested(body); - break; - case "ch": - this.onChannelMessageRequested(body); - break; // alias + const { type, body } = obj; + + switch (type) { + case "readNotification": + this.onReadNotification(body); + break; + case "subNote": + this.onSubscribeNote(body); + break; + case "s": + this.onSubscribeNote(body); + break; // alias + case "sr": + this.onSubscribeNote(body); + this.readNote(body); + break; + case "unsubNote": + this.onUnsubscribeNote(body); + break; + case "un": + this.onUnsubscribeNote(body); + break; // alias + case "connect": + this.onChannelConnectRequested(body); + break; + case "disconnect": + this.onChannelDisconnectRequested(body); + break; + case "channel": + this.onChannelMessageRequested(body); + break; + case "ch": + this.onChannelMessageRequested(body); + break; // alias - // 個々のチャンネルではなくルートレベルでこれらのメッセージを受け取る理由は、 - // クライアントの事情を考慮したとき、入力フォームはノートチャンネルやメッセージのメインコンポーネントとは別 - // なこともあるため、それらのコンポーネントがそれぞれ各チャンネルに接続するようにするのは面倒なため。 - case "typingOnChannel": - this.typingOnChannel(body.channel); - break; - case "typingOnMessaging": - this.typingOnMessaging(body); - break; - } } } @@ -391,75 +265,12 @@ export default class Connection { * クライアントにメッセージ送信 */ public sendMessageToWs(type: string, payload: any) { - console.log(payload, this.isMastodonCompatible); - if (this.isMastodonCompatible) { - if (payload.type === "note") { - this.wsConnection.send( - JSON.stringify({ - stream: [payload.id], - event: "update", - payload: JSON.stringify( - toTextWithReaction( - [Converter.note(payload.body, this.host)], - this.host, - )[0], - ), - }), - ); - this.onSubscribeNote({ - id: payload.body.id, - }); - } else if (payload.type === "reacted" || payload.type === "unreacted") { - // reaction - const client = getClient(this.host, this.accessToken); - client.getStatus(payload.id).then((data) => { - const newPost = toTextWithReaction([data.data], this.host); - for (const stream of this.currentSubscribe) { - this.wsConnection.send( - JSON.stringify({ - stream, - event: "status.update", - payload: JSON.stringify(newPost[0]), - }), - ); - } - }); - } else if (payload.type === "deleted") { - // delete - for (const stream of this.currentSubscribe) { - this.wsConnection.send( - JSON.stringify({ - stream, - event: "delete", - payload: payload.id, - }), - ); - } - } else if (payload.type === "unreadNotification") { - if (payload.id === "user") { - const body = Converter.notification(payload.body, this.host); - if (body.type === "reaction") body.type = "favourite"; - body.status = toTextWithReaction( - body.status ? [body.status] : [], - "", - )[0]; - this.wsConnection.send( - JSON.stringify({ - stream: ["user"], - event: "notification", - payload: JSON.stringify(body), - }), - ); - } - } - } else { - this.wsConnection.send( - JSON.stringify({ - type: type, - body: payload, - }), - ); - } + this.wsConnection.send( + JSON.stringify({ + type: type, + body: payload, + }), + ); } /** @@ -518,30 +329,6 @@ export default class Connection { } } - private typingOnChannel(channel: ChannelModel["id"]) { - if (this.user) { - publishChannelStream(channel, "typing", this.user.id); - } - } - - private typingOnMessaging(param: { - partner?: User["id"]; - group?: UserGroup["id"]; - }) { - if (this.user) { - if (param.partner) { - publishMessagingStream( - param.partner, - this.user.id, - "typing", - this.user.id, - ); - } else if (param.group) { - publishGroupMessagingStream(param.group, "typing", this.user.id); - } - } - } - private async updateFollowing() { const followings = await Followings.find({ where: { diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index 837f42c871..40715d1283 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -9,7 +9,6 @@ import type { DriveFile } from "@/models/entities/drive-file.js"; import type { DriveFolder } from "@/models/entities/drive-folder.js"; import { Emoji } from "@/models/entities/emoji.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"; @@ -86,9 +85,6 @@ export interface MainStreamTypes { readAllUnreadMentions: undefined; unreadSpecifiedNote: Note["id"]; readAllUnreadSpecifiedNotes: undefined; - readAllMessagingMessages: undefined; - messagingMessage: Packed<"MessagingMessage">; - unreadMessagingMessage: Packed<"MessagingMessage">; readAllAntennas: undefined; unreadAntenna: Antenna; readAllAnnouncements: undefined; @@ -156,28 +152,6 @@ 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"]; @@ -232,18 +206,6 @@ export type StreamMessages = { name: `antennaStream:${Antenna["id"]}`; payload: EventUnionFromDictionary; }; - messaging: { - name: `messagingStream:${User["id"]}-${User["id"]}`; - payload: EventUnionFromDictionary; - }; - groupMessaging: { - name: `messagingStream:${UserGroup["id"]}`; - payload: EventUnionFromDictionary; - }; - messagingIndex: { - name: `messagingIndexStream:${User["id"]}`; - payload: EventUnionFromDictionary; - }; admin: { name: `adminStream:${User["id"]}`; payload: EventUnionFromDictionary; diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts index 6ade50d18d..4d4b81d7aa 100644 --- a/packages/backend/src/server/index.ts +++ b/packages/backend/src/server/index.ts @@ -20,8 +20,6 @@ import { createTemp } from "@/misc/create-temp.js"; import { publishMainStream } from "@/services/stream.js"; import * as Acct from "@/misc/acct.js"; import { envOption } from "@/env.js"; -import { koaBody } from 'koa-body'; -import megalodon, { MegalodonInterface } from '@cutls/megalodon'; import activityPub from "./activitypub.js"; import nodeinfo from "./nodeinfo.js"; import wellKnown from "./well-known.js"; @@ -135,34 +133,6 @@ router.get("/verify-email/:code", async (ctx) => { } }); -router.get("/oauth/authorize", async (ctx) => { - const client_id = ctx.request.query.client_id; - console.log(ctx.request.req); - ctx.redirect(Buffer.from(client_id?.toString() || '', 'base64').toString()); -}); - -router.post("/oauth/token", async (ctx) => { - const body: any = ctx.request.body; - const BASE_URL = `${ctx.request.protocol}://${ctx.request.hostname}`; - const generator = (megalodon as any).default; - const client = generator('misskey', BASE_URL, null) as MegalodonInterface; - const m = body.code.match(/^[a-zA-Z0-9-]+/); - if (!m.length) return { error: 'Invalid code' } - try { - const atData = await client.fetchAccessToken(null, body.client_secret, m[0]); - ctx.body = { - access_token: atData.accessToken, - token_type: 'Bearer', - scope: 'read write follow', - created_at: new Date().getTime() / 1000 - }; - } catch (err: any) { - console.error(err); - ctx.status = 401; - ctx.body = err.response.data; - } -}); - // Register router app.use(router.routes()); diff --git a/packages/backend/src/services/messages/create.ts b/packages/backend/src/services/messages/create.ts deleted file mode 100644 index 506f299966..0000000000 --- a/packages/backend/src/services/messages/create.ts +++ /dev/null @@ -1,148 +0,0 @@ -import type { CacheableUser, User } from "@/models/entities/user.js"; -import type { UserGroup } from "@/models/entities/user-group.js"; -import type { DriveFile } from "@/models/entities/drive-file.js"; -import { - MessagingMessages, - UserGroupJoinings, - Mutings, - Users, -} from "@/models/index.js"; -import { genId } from "@/misc/gen-id.js"; -import type { MessagingMessage } from "@/models/entities/messaging-message.js"; -import { - publishMessagingStream, - publishMessagingIndexStream, - publishMainStream, - publishGroupMessagingStream, -} from "@/services/stream.js"; -import { pushNotification } from "@/services/push-notification.js"; -import { Not } from "typeorm"; -import type { Note } from "@/models/entities/note.js"; -import renderNote from "@/remote/activitypub/renderer/note.js"; -import renderCreate from "@/remote/activitypub/renderer/create.js"; -import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import { deliver } from "@/queue/index.js"; - -export async function createMessage( - user: { id: User["id"]; host: User["host"] }, - recipientUser: CacheableUser | undefined, - recipientGroup: UserGroup | undefined, - text: string | null | undefined, - file: DriveFile | null, - uri?: string, -) { - const message = { - id: genId(), - createdAt: new Date(), - fileId: file ? file.id : null, - recipientId: recipientUser ? recipientUser.id : null, - groupId: recipientGroup ? recipientGroup.id : null, - text: text ? text.trim() : null, - userId: user.id, - isRead: false, - reads: [] as any[], - uri, - } as MessagingMessage; - - await MessagingMessages.insert(message); - - const messageObj = await MessagingMessages.pack(message); - - if (recipientUser) { - if (Users.isLocalUser(user)) { - // 自分のストリーム - publishMessagingStream( - message.userId, - recipientUser.id, - "message", - messageObj, - ); - publishMessagingIndexStream(message.userId, "message", messageObj); - publishMainStream(message.userId, "messagingMessage", messageObj); - } - - if (Users.isLocalUser(recipientUser)) { - // 相手のストリーム - publishMessagingStream( - recipientUser.id, - message.userId, - "message", - messageObj, - ); - publishMessagingIndexStream(recipientUser.id, "message", messageObj); - publishMainStream(recipientUser.id, "messagingMessage", messageObj); - } - } else if (recipientGroup) { - // グループのストリーム - publishGroupMessagingStream(recipientGroup.id, "message", messageObj); - - // メンバーのストリーム - const joinings = await UserGroupJoinings.findBy({ - userGroupId: recipientGroup.id, - }); - for (const joining of joinings) { - publishMessagingIndexStream(joining.userId, "message", messageObj); - publishMainStream(joining.userId, "messagingMessage", messageObj); - } - } - - // 2秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する - setTimeout(async () => { - const freshMessage = await MessagingMessages.findOneBy({ id: message.id }); - if (freshMessage == null) return; // メッセージが削除されている場合もある - - if (recipientUser && Users.isLocalUser(recipientUser)) { - if (freshMessage.isRead) return; // 既読 - - //#region ただしミュートされているなら発行しない - const mute = await Mutings.findBy({ - muterId: recipientUser.id, - }); - if (mute.map((m) => m.muteeId).includes(user.id)) return; - //#endregion - - publishMainStream(recipientUser.id, "unreadMessagingMessage", messageObj); - pushNotification(recipientUser.id, "unreadMessagingMessage", messageObj); - } else if (recipientGroup) { - const joinings = await UserGroupJoinings.findBy({ - userGroupId: recipientGroup.id, - userId: Not(user.id), - }); - for (const joining of joinings) { - if (freshMessage.reads.includes(joining.userId)) return; // 既読 - publishMainStream(joining.userId, "unreadMessagingMessage", messageObj); - pushNotification(joining.userId, "unreadMessagingMessage", messageObj); - } - } - }, 2000); - - if ( - recipientUser && - Users.isLocalUser(user) && - Users.isRemoteUser(recipientUser) - ) { - const note = { - id: message.id, - createdAt: message.createdAt, - fileIds: message.fileId ? [message.fileId] : [], - text: message.text, - userId: message.userId, - visibility: "specified", - mentions: [recipientUser].map((u) => u.id), - mentionedRemoteUsers: JSON.stringify( - [recipientUser].map((u) => ({ - uri: u.uri, - username: u.username, - host: u.host, - })), - ), - } as Note; - - const activity = renderActivity( - renderCreate(await renderNote(note, false, true), note), - ); - - deliver(user, activity, recipientUser.inbox); - } - return messageObj; -} diff --git a/packages/backend/src/services/messages/delete.ts b/packages/backend/src/services/messages/delete.ts deleted file mode 100644 index 77caba80ce..0000000000 --- a/packages/backend/src/services/messages/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import config from "@/config/index.js"; -import { MessagingMessages, Users } from "@/models/index.js"; -import type { MessagingMessage } from "@/models/entities/messaging-message.js"; -import { - publishGroupMessagingStream, - publishMessagingStream, -} from "@/services/stream.js"; -import { renderActivity } from "@/remote/activitypub/renderer/index.js"; -import renderDelete from "@/remote/activitypub/renderer/delete.js"; -import renderTombstone from "@/remote/activitypub/renderer/tombstone.js"; -import { deliver } from "@/queue/index.js"; - -export async function deleteMessage(message: MessagingMessage) { - await MessagingMessages.delete(message.id); - postDeleteMessage(message); -} - -async function postDeleteMessage(message: MessagingMessage) { - if (message.recipientId) { - const user = await Users.findOneByOrFail({ id: message.userId }); - const recipient = await Users.findOneByOrFail({ id: message.recipientId }); - - if (Users.isLocalUser(user)) - publishMessagingStream( - message.userId, - message.recipientId, - "deleted", - message.id, - ); - if (Users.isLocalUser(recipient)) - publishMessagingStream( - message.recipientId, - message.userId, - "deleted", - message.id, - ); - - if (Users.isLocalUser(user) && Users.isRemoteUser(recipient)) { - const activity = renderActivity( - renderDelete( - renderTombstone(`${config.url}/notes/${message.id}`), - user, - ), - ); - deliver(user, activity, recipient.inbox); - } - } else if (message.groupId) { - publishGroupMessagingStream(message.groupId, "deleted", message.id); - } -} diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index 0e51ad9675..4d0d17cfd1 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -8,11 +8,8 @@ import { getNoteSummary } from "@/misc/get-note-summary.js"; // Defined also packages/sw/types.ts#L14-L21 type pushNotificationsTypes = { notification: Packed<"Notification">; - unreadMessagingMessage: Packed<"MessagingMessage">; readNotifications: { notificationIds: string[] }; readAllNotifications: undefined; - readAllMessagingMessages: undefined; - readAllMessagingMessagesOfARoom: { userId: string } | { groupId: string }; }; // プッシュメッセージサーバーには文字数制限があるため、内容を削減します diff --git a/packages/backend/src/services/stream.ts b/packages/backend/src/services/stream.ts index f3846feaf1..8e5210d841 100644 --- a/packages/backend/src/services/stream.ts +++ b/packages/backend/src/services/stream.ts @@ -13,11 +13,8 @@ import type { BroadcastTypes, ChannelStreamTypes, DriveStreamTypes, - GroupMessagingStreamTypes, InternalStreamTypes, MainStreamTypes, - MessagingIndexStreamTypes, - MessagingStreamTypes, NoteStreamTypes, UserListStreamTypes, UserStreamTypes, @@ -146,47 +143,6 @@ class Publisher { ); }; - public publishMessagingStream = ( - userId: User["id"], - otherpartyId: User["id"], - type: K, - value?: MessagingStreamTypes[K], - ): void => { - this.publish( - `messagingStream:${userId}-${otherpartyId}`, - type, - typeof value === "undefined" ? null : value, - ); - }; - - public publishGroupMessagingStream = < - K extends keyof GroupMessagingStreamTypes, - >( - groupId: UserGroup["id"], - type: K, - value?: GroupMessagingStreamTypes[K], - ): void => { - this.publish( - `messagingStream:${groupId}`, - type, - typeof value === "undefined" ? null : value, - ); - }; - - public publishMessagingIndexStream = < - K extends keyof MessagingIndexStreamTypes, - >( - userId: User["id"], - type: K, - value?: MessagingIndexStreamTypes[K], - ): void => { - this.publish( - `messagingIndexStream:${userId}`, - type, - typeof value === "undefined" ? null : value, - ); - }; - public publishNotesStream = (note: Note): void => { this.publish("notesStream", null, note); }; @@ -218,9 +174,4 @@ export const publishNotesStream = publisher.publishNotesStream; export const publishChannelStream = publisher.publishChannelStream; export const publishUserListStream = publisher.publishUserListStream; export const publishAntennaStream = publisher.publishAntennaStream; -export const publishMessagingStream = publisher.publishMessagingStream; -export const publishGroupMessagingStream = - publisher.publishGroupMessagingStream; -export const publishMessagingIndexStream = - publisher.publishMessagingIndexStream; export const publishAdminStream = publisher.publishAdminStream; diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts index e6bde24d1a..2e9edea408 100644 --- a/packages/client/src/init.ts +++ b/packages/client/src/init.ts @@ -460,15 +460,6 @@ import { getAccountFromId } from "@/scripts/get-account-from-id"; updateAccount({ hasUnreadSpecifiedNotes: false }); }); - main.on("readAllMessagingMessages", () => { - updateAccount({ hasUnreadMessagingMessage: false }); - }); - - main.on("unreadMessagingMessage", () => { - updateAccount({ hasUnreadMessagingMessage: true }); - sound.play("chatBg"); - }); - main.on("readAllAntennas", () => { updateAccount({ hasUnreadAntenna: false }); }); diff --git a/packages/client/src/navbar.ts b/packages/client/src/navbar.ts index 5b116cee1b..30b33c4522 100644 --- a/packages/client/src/navbar.ts +++ b/packages/client/src/navbar.ts @@ -18,13 +18,6 @@ export const navbarItemDef = reactive({ indicated: computed(() => $i?.hasUnreadNotification), to: "/my/notifications", }, - messaging: { - title: "messaging", - icon: "ph-chats-teardrop-bold ph-lg", - show: computed(() => $i != null), - indicated: computed(() => $i?.hasUnreadMessagingMessage), - to: "/my/messaging", - }, drive: { title: "drive", icon: "ph-cloud-bold ph-lg", diff --git a/packages/client/src/pages/messaging/index.vue b/packages/client/src/pages/messaging/index.vue deleted file mode 100644 index af2baf8525..0000000000 --- a/packages/client/src/pages/messaging/index.vue +++ /dev/null @@ -1,220 +0,0 @@ - - - - - diff --git a/packages/client/src/pages/messaging/messaging-room.form.vue b/packages/client/src/pages/messaging/messaging-room.form.vue deleted file mode 100644 index 6e489d8952..0000000000 --- a/packages/client/src/pages/messaging/messaging-room.form.vue +++ /dev/null @@ -1,361 +0,0 @@ - - - - - diff --git a/packages/client/src/pages/messaging/messaging-room.message.vue b/packages/client/src/pages/messaging/messaging-room.message.vue deleted file mode 100644 index 051406eaea..0000000000 --- a/packages/client/src/pages/messaging/messaging-room.message.vue +++ /dev/null @@ -1,329 +0,0 @@ - - - - - diff --git a/packages/client/src/pages/messaging/messaging-room.vue b/packages/client/src/pages/messaging/messaging-room.vue deleted file mode 100644 index 11f944860b..0000000000 --- a/packages/client/src/pages/messaging/messaging-room.vue +++ /dev/null @@ -1,400 +0,0 @@ - - - - - diff --git a/packages/client/src/router.ts b/packages/client/src/router.ts index 48aad0820f..2c5d80fa1f 100644 --- a/packages/client/src/router.ts +++ b/packages/client/src/router.ts @@ -542,22 +542,6 @@ export const routes = [ component: page(() => import("./pages/favorites.vue")), loginRequired: true, }, - { - name: "messaging", - path: "/my/messaging", - component: page(() => import("./pages/messaging/index.vue")), - loginRequired: true, - }, - { - path: "/my/messaging/:userAcct", - component: page(() => import("./pages/messaging/messaging-room.vue")), - loginRequired: true, - }, - { - path: "/my/messaging/group/:groupId", - component: page(() => import("./pages/messaging/messaging-room.vue")), - loginRequired: true, - }, { path: "/my/drive/folder/:folder", component: page(() => import("./pages/drive.vue")), diff --git a/packages/client/src/scripts/get-note-menu.ts b/packages/client/src/scripts/get-note-menu.ts index e8e726ab3b..f68946328e 100644 --- a/packages/client/src/scripts/get-note-menu.ts +++ b/packages/client/src/scripts/get-note-menu.ts @@ -1,6 +1,5 @@ -import { defineAsyncComponent, Ref, inject } from "vue"; +import { defineAsyncComponent, Ref } from "vue"; import * as misskey from "calckey-js"; -import { pleaseLogin } from "./please-login"; import { $i } from "@/account"; import { i18n } from "@/i18n"; import { instance } from "@/instance"; diff --git a/packages/client/src/scripts/get-user-menu.ts b/packages/client/src/scripts/get-user-menu.ts index bca3b198a6..032198241a 100644 --- a/packages/client/src/scripts/get-user-menu.ts +++ b/packages/client/src/scripts/get-user-menu.ts @@ -232,15 +232,6 @@ export function getUserMenu(user, router: Router = mainRouter) { os.post({ specified: user }); }, }, - meId !== user.id - ? { - type: "link", - icon: "ph-chats-teardrop-bold ph-lg", - text: i18n.ts.startMessaging, - to: `/my/messaging/${Acct.toString(user)}`, - } - : undefined, - null, { icon: "ph-list-bullets-bold ph-lg", text: i18n.ts.addToList, diff --git a/packages/client/src/store.ts b/packages/client/src/store.ts index 0e23ae1b7e..ddf2cf24ca 100644 --- a/packages/client/src/store.ts +++ b/packages/client/src/store.ts @@ -86,7 +86,6 @@ export const defaultStore = markRaw( "notifications", undefined, "followRequests", - "messaging", "explore", "favorites", "channels", diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts index 01b9ab5888..532f5dd829 100644 --- a/packages/sw/src/scripts/create-notification.ts +++ b/packages/sw/src/scripts/create-notification.ts @@ -305,33 +305,6 @@ async function composeNotification( default: return null; } - case "unreadMessagingMessage": - if (data.body.groupId === null) { - return [ - t("_notification.youGotMessagingMessageFromUser", { - name: getUserName(data.body.user), - }), - { - icon: data.body.user.avatarUrl, - badge: iconUrl("comments"), - tag: `messaging:user:${data.body.userId}`, - data, - renotify: true, - }, - ]; - } - return [ - t("_notification.youGotMessagingMessageFromGroup", { - name: data.body.group.name, - }), - { - icon: data.body.user.avatarUrl, - badge: iconUrl("comments"), - tag: `messaging:group:${data.body.groupId}`, - data, - renotify: true, - }, - ]; default: return null; } diff --git a/packages/sw/src/scripts/operations.ts b/packages/sw/src/scripts/operations.ts index a192a9bd7e..20d52ca00b 100644 --- a/packages/sw/src/scripts/operations.ts +++ b/packages/sw/src/scripts/operations.ts @@ -6,7 +6,6 @@ declare var self: ServiceWorkerGlobalScope; import * as Misskey from "calckey-js"; import { SwMessage, swMessageOrderType } from "@/types"; -import { acct as getAcct } from "@/filters/user"; import { getAccountFromId } from "@/scripts/get-account-from-id"; import { getUrlWithLoginId } from "@/scripts/login-id"; @@ -36,18 +35,6 @@ export function openNote(noteId: string, loginId: string) { return openClient("push", `/notes/${noteId}`, loginId, { noteId }); } -export async function openChat(body: any, loginId: string) { - if (body.groupId === null) { - return openClient("push", `/my/messaging/${getAcct(body.user)}`, loginId, { - body, - }); - } else { - return openClient("push", `/my/messaging/group/${body.groupId}`, loginId, { - body, - }); - } -} - // post-formのオプションから投稿フォームを開く export async function openPost(options: any, loginId: string) { // クエリを作成しておく diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts index 0733400fc3..3e693bfdf3 100644 --- a/packages/sw/src/sw.ts +++ b/packages/sw/src/sw.ts @@ -2,7 +2,6 @@ declare var self: ServiceWorkerGlobalScope; import { createEmptyNotification, - createNotification, } from "@/scripts/create-notification"; import { swLang } from "@/scripts/lang"; import { swNotificationRead } from "@/scripts/notification-read"; @@ -65,25 +64,11 @@ self.addEventListener("push", (ev) => { switch (data.type) { // case 'driveFileCreated': case "notification": - case "unreadMessagingMessage": - // 1日以上経過している場合は無視 - if (new Date().getTime() - data.dateTime > 1000 * 60 * 60 * 24) - break; - - // クライアントがあったらストリームに接続しているということなので通知しない - if (clients.length !== 0) break; - - return createNotification(data); case "readAllNotifications": for (const n of await self.registration.getNotifications()) { if (n?.data?.type === "notification") n.close(); } break; - case "readAllMessagingMessages": - for (const n of await self.registration.getNotifications()) { - if (n?.data?.type === "unreadMessagingMessage") n.close(); - } - break; case "readNotifications": for (const n of await self.registration.getNotifications()) { if (data.body?.notificationIds?.includes(n.data.body.id)) { @@ -91,18 +76,6 @@ self.addEventListener("push", (ev) => { } } break; - case "readAllMessagingMessagesOfARoom": - for (const n of await self.registration.getNotifications()) { - if ( - n.data.type === "unreadMessagingMessage" && - ("userId" in data.body - ? data.body.userId === n.data.body.userId - : data.body.groupId === n.data.body.groupId) - ) { - n.close(); - } - } - break; } return createEmptyNotification(); @@ -210,9 +183,6 @@ self.addEventListener( } } break; - case "unreadMessagingMessage": - client = await swos.openChat(data.body, id); - break; } if (client) { diff --git a/packages/sw/src/types.ts b/packages/sw/src/types.ts index 984076dbec..2110a78043 100644 --- a/packages/sw/src/types.ts +++ b/packages/sw/src/types.ts @@ -13,11 +13,8 @@ export type SwMessage = { // Defined also @/services/push-notification.ts#L7-L14 type pushNotificationDataSourceMap = { notification: Misskey.entities.Notification; - unreadMessagingMessage: Misskey.entities.MessagingMessage; readNotifications: { notificationIds: string[] }; readAllNotifications: undefined; - readAllMessagingMessages: undefined; - readAllMessagingMessagesOfARoom: { userId: string } | { groupId: string }; }; export type pushNotificationData< diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 476fd2fbbb..cb36e2d0cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,8 @@ importers: .: specifiers: - '@bull-board/api': ^4.10.2 - '@bull-board/ui': ^4.10.2 + '@bull-board/api': ^4.12.2 + '@bull-board/ui': ^4.12.2 '@tensorflow/tfjs': ^3.21.0 '@types/gulp': 4.0.10 '@types/gulp-rename': 2.0.1 @@ -29,8 +29,8 @@ importers: start-server-and-test: 1.15.2 typescript: 4.9.4 dependencies: - '@bull-board/api': 4.10.2 - '@bull-board/ui': 4.10.2 + '@bull-board/api': 4.12.2 + '@bull-board/ui': 4.12.2 '@tensorflow/tfjs': 3.21.0_seedrandom@3.0.5 calckey-js: 0.0.20 js-yaml: 4.1.0 @@ -672,6 +672,12 @@ packages: redis-info: 3.1.0 dev: false + /@bull-board/api/4.12.2: + resolution: {integrity: sha512-efF8K1pvfEEft2ELQwCBe/a225vHufCjM2hfcyvmIG/SUX6TlKQFUFZ1+KV0wenD9wxvUVb5wxUu6on+HrZiVg==} + dependencies: + redis-info: 3.1.0 + dev: false + /@bull-board/koa/4.10.2_6tybghmia4wsnt33xeid7y4rby: resolution: {integrity: sha512-gabPtsMOt2SQHkS5VcY1q/FCpbBRFiFrbWbcouZ7zWKg413J8nG+yErz3pc0rbmp23kbKX6wTG/diWKhE7EWbA==} dependencies: @@ -746,6 +752,12 @@ packages: '@bull-board/api': 4.10.2 dev: false + /@bull-board/ui/4.12.2: + resolution: {integrity: sha512-jB/OOEhg+DUL6ssmtQYTK+iYd3iy68bbozOp+q2xVUC4V7zeFmYF25sIApYFTNfbjuUMesAVOiX4u0gNEo/J7w==} + dependencies: + '@bull-board/api': 4.12.2 + dev: false + /@colors/colors/1.5.0: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -1191,6 +1203,15 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/trace-mapping': 0.3.17 + /@jridgewell/gen-mapping/0.3.3: + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.18 + dev: true + /@jridgewell/resolve-uri/3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} @@ -1206,15 +1227,33 @@ packages: '@jridgewell/trace-mapping': 0.3.17 dev: true + /@jridgewell/source-map/0.3.3: + resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.18 + dev: true + /@jridgewell/sourcemap-codec/1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + /@jridgewell/sourcemap-codec/1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true + /@jridgewell/trace-mapping/0.3.17: resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 + /@jridgewell/trace-mapping/0.3.18: + resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: @@ -1865,7 +1904,7 @@ packages: '@types/webgl-ext': 0.0.30 '@webgpu/types': 0.1.16 long: 4.0.0 - node-fetch: 2.6.8 + node-fetch: 2.6.9 seedrandom: 3.0.5 transitivePeerDependencies: - encoding @@ -1894,8 +1933,8 @@ packages: seedrandom: ^3.0.5 dependencies: '@tensorflow/tfjs-core': 3.21.0 - '@types/node-fetch': 2.6.2 - node-fetch: 2.6.8 + '@types/node-fetch': 2.6.3 + node-fetch: 2.6.9 seedrandom: 3.0.5 string_decoder: 1.3.0 transitivePeerDependencies: @@ -1965,7 +2004,7 @@ packages: '@tensorflow/tfjs-layers': 3.21.0_aipmo6igpprgzt4umpaa3m6sn4 argparse: 1.0.10 chalk: 4.1.2 - core-js: 3.27.1 + core-js: 3.30.1 regenerator-runtime: 0.13.11 yargs: 16.2.0 transitivePeerDependencies: @@ -2138,11 +2177,18 @@ packages: '@types/node': 18.11.18 dev: false - /@types/glob-stream/6.1.1: - resolution: {integrity: sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==} + /@types/glob-stream/6.1.2: + resolution: {integrity: sha512-EIJSLP/nGyMzD8aFhJljO9nv3EmQ10xk1+dl+i15AITrcWLhhTTPmNMFK0TWcGRvVYuSlA1VPi1fe8tbgDsUhg==} dependencies: - '@types/glob': 8.0.0 - '@types/node': 18.11.18 + '@types/glob': 7.2.0 + '@types/node': 18.15.12 + dev: true + + /@types/glob/7.2.0: + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 18.15.12 dev: true /@types/glob/8.0.0: @@ -2152,10 +2198,17 @@ packages: '@types/node': 18.11.18 dev: true + /@types/glob/8.1.0: + resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 18.15.12 + dev: true + /@types/gulp-rename/2.0.1: resolution: {integrity: sha512-9ZjeS2RHEnmBmTcyi2+oeye3BgCsWhvi4uv3qCnAg8i6plOuRdaeNxjOves0ELysEXYLBl7bCl5fbVs7AZtgTA==} dependencies: - '@types/node': 18.11.18 + '@types/node': 18.15.12 '@types/vinyl': 2.0.7 dev: true @@ -2163,7 +2216,7 @@ packages: resolution: {integrity: sha512-spgZHJFqiEJGwqGlf7T/k4nkBpBcLgP7T0EfN6G2vvnhUfvd4uO1h8RwpXOE8x/54DVYUs1XCAtBHkX/R3axAQ==} dependencies: '@types/undertaker': 1.2.8 - '@types/vinyl-fs': 2.4.12 + '@types/vinyl-fs': 3.0.1 chokidar: 3.5.3 dev: true @@ -2382,6 +2435,13 @@ packages: form-data: 3.0.1 dev: false + /@types/node-fetch/2.6.3: + resolution: {integrity: sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==} + dependencies: + '@types/node': 18.15.12 + form-data: 3.0.1 + dev: false + /@types/node-fetch/3.0.3: resolution: {integrity: sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==} deprecated: This is a stub types definition. node-fetch provides its own type definitions, so you do not need this installed. @@ -2391,10 +2451,18 @@ packages: /@types/node/14.18.36: resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==} + dev: false + + /@types/node/14.18.42: + resolution: {integrity: sha512-xefu+RBie4xWlK8hwAzGh3npDz/4VhF6icY/shU+zv/1fNn+ZVG7T7CRwe9LId9sAYRPxI+59QBPuKL3WpyGRg==} + dev: true /@types/node/18.11.18: resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} + /@types/node/18.15.12: + resolution: {integrity: sha512-Wha1UwsB3CYdqUm2PPzh/1gujGCNtWVUYF0mB00fJFoR4gTyWTDPjSm+zBF787Ahw8vSGgBja90MkgFwvB86Dg==} + /@types/nodemailer/6.4.7: resolution: {integrity: sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==} dependencies: @@ -2464,6 +2532,13 @@ packages: dependencies: '@types/node': 18.11.18 + /@types/rimraf/2.0.5: + resolution: {integrity: sha512-YyP+VfeaqAyFmXoTh3HChxOQMyjByRMsHU7kc5KOJkSlXudhMhQIALbYV7rHh/l8d2lX3VUQzprrcAgWdRuU8g==} + dependencies: + '@types/glob': 8.1.0 + '@types/node': 18.15.12 + dev: true + /@types/sanitize-html/2.8.0: resolution: {integrity: sha512-Uih6caOm3DsBYnVGOYn0A9NoTNe1c4aPStmHC/YA2JrpP9kx//jzaRcIklFvSpvVQEcpl/ZCr4DgISSf/YxTvg==} dependencies: @@ -2539,7 +2614,7 @@ packages: /@types/undertaker/1.2.8: resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} dependencies: - '@types/node': 18.11.18 + '@types/node': 18.15.12 '@types/undertaker-registry': 1.0.1 async-done: 1.3.2 dev: true @@ -2548,11 +2623,12 @@ packages: resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} dev: true - /@types/vinyl-fs/2.4.12: - resolution: {integrity: sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==} + /@types/vinyl-fs/3.0.1: + resolution: {integrity: sha512-me2Gcxw23pZp62oqPoiTDDMz/txEmtEZzXM/D/VTr+xUX4LiNA+nQPs38SSPu5KHnsaEER4HEtzWU5qJRXigfA==} dependencies: - '@types/glob-stream': 6.1.1 - '@types/node': 18.11.18 + '@types/glob-stream': 6.1.2 + '@types/node': 18.15.12 + '@types/rimraf': 2.0.5 '@types/vinyl': 2.0.7 dev: true @@ -2560,7 +2636,7 @@ packages: resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} dependencies: '@types/expect': 1.20.4 - '@types/node': 18.11.18 + '@types/node': 18.15.12 dev: true /@types/web-push/3.3.2: @@ -2599,7 +2675,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 18.11.18 + '@types/node': 14.18.42 dev: true optional: true @@ -2885,6 +2961,12 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + /acorn/8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /adm-zip/0.5.10: resolution: {integrity: sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==} engines: {node: '>=6.0'} @@ -3288,7 +3370,7 @@ packages: resolution: {integrity: sha512-WKExI/eSGgGAkWAO+wMVdFObZV7hQen54UpD1kCCTN3tvlL3W1jL4+lPP/M7MwoP7Q4RHzKtO3JQ4HxYEcd+xQ==} dependencies: browserslist: 1.7.7 - caniuse-db: 1.0.30001443 + caniuse-db: 1.0.30001480 normalize-range: 0.1.2 num2fraction: 1.2.2 postcss: 5.2.18 @@ -3343,7 +3425,7 @@ packages: /axios/0.25.0_debug@4.3.4: resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} dependencies: - follow-redirects: 1.15.2 + follow-redirects: 1.15.2_debug@4.3.4 transitivePeerDependencies: - debug dev: true @@ -3600,8 +3682,8 @@ packages: deprecated: Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools. hasBin: true dependencies: - caniuse-db: 1.0.30001443 - electron-to-chromium: 1.4.284 + caniuse-db: 1.0.30001480 + electron-to-chromium: 1.4.368 dev: true /browserslist/4.21.4: @@ -3826,13 +3908,13 @@ packages: autobind-decorator: 2.4.0 eventemitter3: 4.0.7 reconnecting-websocket: 4.4.0 - semver: 7.3.8 + semver: 7.5.0 /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: function-bind: 1.1.1 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.0 /callsites/3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -3857,13 +3939,13 @@ packages: resolution: {integrity: sha512-SBTl70K0PkDUIebbkXrxWqZlHNs0wRgRD6QZ8guctShjbh63gEPfF+Wj0Yw+75f5Y8tSzqAI/NcisYv/cCah2Q==} dependencies: browserslist: 1.7.7 - caniuse-db: 1.0.30001443 + caniuse-db: 1.0.30001480 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 dev: true - /caniuse-db/1.0.30001443: - resolution: {integrity: sha512-4KKthVYyooNIOhO1w0OJ13EhEwOGECMrZdkeyDydhvYXaTDA3WdhR8amoJnAgpSgcCR26aOAWk6N9ANVYlv2oQ==} + /caniuse-db/1.0.30001480: + resolution: {integrity: sha512-DVj/w8brn4D//RjICBR23GP/4y28fk2Bsb3PDN1orV3/7rEB8czfr0TxYBY0weRPwUsj6n9+kMoPxUD7wyvcJg==} dev: true /caniuse-lite/1.0.30001443: @@ -4045,8 +4127,8 @@ packages: engines: {node: '>=6.0'} dev: true - /ci-info/3.7.1: - resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==} + /ci-info/3.8.0: + resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} dev: true @@ -4176,7 +4258,7 @@ packages: dependencies: inherits: 2.0.4 process-nextick-args: 2.0.1 - readable-stream: 2.3.7 + readable-stream: 2.3.8 dev: true /cluster-key-slot/1.1.1: @@ -4294,8 +4376,8 @@ packages: resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} dev: false - /colorette/2.0.19: - resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} + /colorette/2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} dev: true /colormin/1.1.2: @@ -4372,7 +4454,7 @@ packages: dependencies: buffer-from: 1.1.2 inherits: 2.0.4 - readable-stream: 2.3.7 + readable-stream: 2.3.8 typedarray: 0.0.6 /condense-newlines/0.2.1: @@ -4780,6 +4862,11 @@ packages: resolution: {integrity: sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==} requiresBuild: true + /core-js/3.30.1: + resolution: {integrity: sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==} + requiresBuild: true + dev: false + /core-util-is/1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -4960,7 +5047,7 @@ packages: dependencies: '@cypress/request': 2.88.11 '@cypress/xvfb': 1.2.4_supports-color@8.1.1 - '@types/node': 14.18.36 + '@types/node': 14.18.42 '@types/sinonjs__fake-timers': 8.1.1 '@types/sizzle': 2.3.3 arch: 2.2.0 @@ -4990,12 +5077,12 @@ packages: listr2: 3.14.0_enquirer@2.3.6 lodash: 4.17.21 log-symbols: 4.1.0 - minimist: 1.2.7 + minimist: 1.2.8 ospath: 1.2.2 pretty-bytes: 5.6.0 proxy-from-env: 1.0.0 request-progress: 3.0.0 - semver: 7.3.8 + semver: 7.5.0 supports-color: 8.1.1 tmp: 0.2.1 untildify: 4.0.0 @@ -5241,8 +5328,8 @@ packages: engines: {node: '>=10'} dev: false - /define-properties/1.1.4: - resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} + /define-properties/1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} engines: {node: '>= 0.4'} dependencies: has-property-descriptors: 1.0.0 @@ -5460,7 +5547,7 @@ packages: dependencies: end-of-stream: 1.4.4 inherits: 2.0.4 - readable-stream: 2.3.7 + readable-stream: 2.3.8 stream-shift: 1.0.1 dev: true @@ -5508,6 +5595,10 @@ packages: resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} dev: true + /electron-to-chromium/1.4.368: + resolution: {integrity: sha512-e2aeCAixCj9M7nJxdB/wDjO6mbYX+lJJxSJCXDzlr5YPGYVofuJwGN9nKg2o6wWInjX6XmxRinn3AeJMK81ltw==} + dev: true + /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -6298,7 +6389,7 @@ packages: resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} dependencies: inherits: 2.0.4 - readable-stream: 2.3.7 + readable-stream: 2.3.8 dev: true /follow-redirects/1.15.2: @@ -6309,6 +6400,19 @@ packages: peerDependenciesMeta: debug: optional: true + dev: false + + /follow-redirects/1.15.2_debug@4.3.4: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4 + dev: true /for-each/0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -6416,7 +6520,7 @@ packages: engines: {node: '>=10'} dependencies: at-least-node: 1.0.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 dev: true @@ -6439,7 +6543,7 @@ packages: resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==} engines: {node: '>= 0.10'} dependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 through2: 2.0.5 dev: true @@ -6520,6 +6624,14 @@ packages: function-bind: 1.1.1 has: 1.0.3 has-symbols: 1.0.3 + dev: false + + /get-intrinsic/1.2.0: + resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.3 /get-paths/0.0.7: resolution: {integrity: sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA==} @@ -6641,7 +6753,7 @@ packages: is-negated-glob: 1.0.0 ordered-read-streams: 1.0.1 pumpify: 1.5.1 - readable-stream: 2.3.7 + readable-stream: 2.3.8 remove-trailing-separator: 1.1.0 to-absolute-glob: 2.0.2 unique-stream: 2.3.1 @@ -6827,6 +6939,10 @@ packages: /graceful-fs/4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + /graceful-fs/4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true + /grapheme-splitter/1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} @@ -6876,7 +6992,7 @@ packages: resolution: {integrity: sha512-SVSF7ikuWKhpAW4l4wapAqPPSToJoiNKsbDoUnRrSgwZHH7lH8pbPeQj1aOVYQrbZKhfSVBxVW+Py7vtulRktw==} engines: {node: '>=10'} dependencies: - '@types/node': 18.11.18 + '@types/node': 18.15.12 '@types/vinyl': 2.0.7 istextorbinary: 3.3.0 replacestream: 4.0.3 @@ -6888,7 +7004,7 @@ packages: engines: {node: '>=10'} dependencies: plugin-error: 1.0.1 - terser: 5.16.1 + terser: 5.17.1 through2: 4.0.2 vinyl-sourcemaps-apply: 0.2.1 dev: true @@ -6956,7 +7072,7 @@ packages: /has-property-descriptors/1.0.0: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.0 dev: true /has-symbol-support-x/1.4.2: @@ -7464,7 +7580,7 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true dependencies: - ci-info: 3.7.1 + ci-info: 3.8.0 dev: true /is-core-module/2.11.0: @@ -7472,6 +7588,12 @@ packages: dependencies: has: 1.0.3 + /is-core-module/2.12.0: + resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==} + dependencies: + has: 1.0.3 + dev: true + /is-data-descriptor/0.1.4: resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} engines: {node: '>=0.10.0'} @@ -7802,8 +7924,8 @@ packages: engines: {node: '>= 0.6.0'} dev: false - /joi/17.7.0: - resolution: {integrity: sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==} + /joi/17.9.1: + resolution: {integrity: sha512-FariIi9j6QODKATGBrEX7HZcja8Bsh3rfdGYy/Sb65sGlZWK/QWesU1ghk7aJWDj95knjXlQfSmzFSPPkLVsfw==} dependencies: '@hapi/hoek': 9.3.0 '@hapi/topo': 5.1.0 @@ -7985,7 +8107,7 @@ packages: dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 dev: true /jsonld/6.0.0: @@ -8416,7 +8538,7 @@ packages: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} dependencies: - readable-stream: 2.3.7 + readable-stream: 2.3.8 /lcid/1.0.0: resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} @@ -8458,7 +8580,7 @@ packages: is-plain-object: 2.0.4 object.map: 1.0.1 rechoir: 0.6.2 - resolve: 1.22.1 + resolve: 1.22.2 transitivePeerDependencies: - supports-color dev: true @@ -8477,7 +8599,7 @@ packages: optional: true dependencies: cli-truncate: 2.1.0 - colorette: 2.0.19 + colorette: 2.0.20 enquirer: 2.3.6 log-update: 4.0.0 p-map: 4.0.0 @@ -8512,7 +8634,7 @@ packages: resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} engines: {node: '>=0.10.0'} dependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 parse-json: 2.2.0 pify: 2.3.0 pinkie-promise: 2.0.1 @@ -8780,7 +8902,7 @@ packages: dependencies: findup-sync: 2.0.0 micromatch: 3.1.10 - resolve: 1.22.1 + resolve: 1.22.2 stack-trace: 0.0.10 transitivePeerDependencies: - supports-color @@ -8906,6 +9028,9 @@ packages: /minimist/1.2.7: resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} + /minimist/1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + /minipass-collect/1.0.2: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} engines: {node: '>= 8'} @@ -9005,7 +9130,7 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true dependencies: - minimist: 1.2.7 + minimist: 1.2.8 /mkdirp/1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} @@ -9247,6 +9372,18 @@ packages: whatwg-url: 5.0.0 dev: false + /node-fetch/2.6.9: + resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + /node-fetch/3.3.0: resolution: {integrity: sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -9319,7 +9456,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.1 + resolve: 1.22.2 semver: 5.7.1 validate-npm-package-license: 3.0.4 dev: true @@ -9503,7 +9640,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 - define-properties: 1.1.4 + define-properties: 1.2.0 has-symbols: 1.0.3 object-keys: 1.1.1 dev: true @@ -9615,7 +9752,7 @@ packages: /ordered-read-streams/1.0.1: resolution: {integrity: sha512-Z87aSjx3r5c0ZB7bcJqIgIRX5bxR7A4aSzvIbaxd0oTkWBCOoKfuGHiKj60CHVUgg1Phm5yMZzBdt8XqRs73Mw==} dependencies: - readable-stream: 2.3.7 + readable-stream: 2.3.8 dev: true /os-filter-obj/2.0.0: @@ -9870,7 +10007,7 @@ packages: resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} engines: {node: '>=0.10.0'} dependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 pify: 2.3.0 pinkie-promise: 2.0.1 dev: true @@ -10539,6 +10676,10 @@ packages: resolution: {integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==} engines: {node: '>=6'} + /punycode/2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + /pureimage/0.3.15: resolution: {integrity: sha512-QpQYEV8nxVb84en7D0nKXwG0bdmwmlsSg9QnqxpEOExvUXdbmo6Lw/UoxSXD9z+ryvWDkgWqZsIM3iPCAh4dXg==} engines: {node: '>=0.8'} @@ -10733,6 +10874,17 @@ packages: string_decoder: 1.1.1 util-deprecate: 1.0.2 + /readable-stream/2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + /readable-stream/3.6.0: resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} engines: {node: '>= 6'} @@ -10740,6 +10892,16 @@ packages: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 + dev: false + + /readable-stream/3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true /readable-web-to-node-stream/3.0.2: resolution: {integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==} @@ -10764,7 +10926,7 @@ packages: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} dependencies: - resolve: 1.22.1 + resolve: 1.22.2 dev: true /reconnecting-websocket/4.4.0: @@ -10893,7 +11055,7 @@ packages: dependencies: escape-string-regexp: 1.0.5 object-assign: 4.1.1 - readable-stream: 2.3.7 + readable-stream: 2.3.8 dev: true /request-progress/3.0.0: @@ -10997,6 +11159,15 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /resolve/1.22.2: + resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + hasBin: true + dependencies: + is-core-module: 2.12.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /responselike/1.0.2: resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} dependencies: @@ -11106,7 +11277,7 @@ packages: /rxjs/7.8.0: resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} dependencies: - tslib: 2.4.1 + tslib: 2.5.0 dev: true /s-age/1.1.2: @@ -11229,6 +11400,13 @@ packages: dependencies: lru-cache: 6.0.0 + /semver/7.5.0: + resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + /serialize-javascript/6.0.0: resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} dependencies: @@ -11314,7 +11492,7 @@ packages: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: call-bind: 1.0.2 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.0 object-inspect: 1.12.3 /sigmund/1.0.1: @@ -11496,11 +11674,11 @@ packages: engines: {node: '>= 0.10'} dev: true - /spdx-correct/3.1.1: - resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + /spdx-correct/3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.12 + spdx-license-ids: 3.0.13 dev: true /spdx-exceptions/2.3.0: @@ -11511,11 +11689,11 @@ packages: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: spdx-exceptions: 2.3.0 - spdx-license-ids: 3.0.12 + spdx-license-ids: 3.0.13 dev: true - /spdx-license-ids/3.0.12: - resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + /spdx-license-ids/3.0.13: + resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==} dev: true /speakeasy/2.0.0: @@ -11980,6 +12158,17 @@ packages: source-map-support: 0.5.21 dev: true + /terser/5.17.1: + resolution: {integrity: sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + '@jridgewell/source-map': 0.3.3 + acorn: 8.8.2 + commander: 2.20.3 + source-map-support: 0.5.21 + dev: true + /tesseract.js-core/3.0.2: resolution: {integrity: sha512-2fD76ka9nO/C616R0fq+M9Zu91DA3vEfyozp0jlxaJOBmpfeprtgRP3cqVweZh2darE1kK/DazoxZ65g7WU99Q==} dev: false @@ -12060,14 +12249,14 @@ packages: /through2/2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} dependencies: - readable-stream: 2.3.7 + readable-stream: 2.3.8 xtend: 4.0.2 dev: true /through2/4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} dependencies: - readable-stream: 3.6.0 + readable-stream: 3.6.2 dev: true /time-stamp/1.1.0: @@ -12163,7 +12352,7 @@ packages: engines: {node: '>=0.8'} dependencies: psl: 1.9.0 - punycode: 2.2.0 + punycode: 2.3.0 /tough-cookie/4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} @@ -12270,6 +12459,11 @@ packages: /tslib/2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + dev: false + + /tslib/2.5.0: + resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + dev: true /tsscmp/1.0.6: resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} @@ -12675,7 +12869,7 @@ packages: /validate-npm-package-license/3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: - spdx-correct: 3.1.1 + spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 dev: true @@ -12711,13 +12905,13 @@ packages: dependencies: fs-mkdirp-stream: 1.0.0 glob-stream: 6.1.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 is-valid-glob: 1.0.0 lazystream: 1.0.1 lead: 1.0.0 object.assign: 4.1.4 pumpify: 1.5.1 - readable-stream: 2.3.7 + readable-stream: 2.3.8 remove-bom-buffer: 3.0.0 remove-bom-stream: 1.2.0 resolve-options: 1.1.0 @@ -12734,7 +12928,7 @@ packages: dependencies: append-buffer: 1.0.2 convert-source-map: 1.9.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 normalize-path: 2.1.1 now-and-later: 2.0.1 remove-bom-buffer: 3.0.0 @@ -12858,9 +13052,9 @@ packages: hasBin: true dependencies: axios: 0.25.0_debug@4.3.4 - joi: 17.7.0 + joi: 17.9.1 lodash: 4.17.21 - minimist: 1.2.7 + minimist: 1.2.8 rxjs: 7.8.0 transitivePeerDependencies: - debug