@@ -56,6 +56,7 @@ import {
5656import { getXForwardedRequest } from "@hongminhee/x-forwarded-fetch" ;
5757import { getLogger } from "@logtape/logtape" ;
5858import { extension } from "@std/media-types/extension" ;
59+ import { parseMediaType } from "@std/media-types/parse-media-type" ;
5960import metadata from "../deno.json" with { type : "json" } ;
6061import type { Bot , CreateBotOptions , PagesOptions } from "./bot.ts" ;
6162import {
@@ -70,6 +71,7 @@ import type {
7071 LikeEventHandler ,
7172 MentionEventHandler ,
7273 MessageEventHandler ,
74+ QuoteEventHandler ,
7375 ReactionEventHandler ,
7476 RejectEventHandler ,
7577 ReplyEventHandler ,
@@ -124,6 +126,7 @@ export class BotImpl<TContextData> implements Bot<TContextData> {
124126 onRejectFollow ?: RejectEventHandler < TContextData > ;
125127 onMention ?: MentionEventHandler < TContextData > ;
126128 onReply ?: ReplyEventHandler < TContextData > ;
129+ onQuote ?: QuoteEventHandler < TContextData > ;
127130 onMessage ?: MessageEventHandler < TContextData > ;
128131 onSharedMessage ?: SharedMessageEventHandler < TContextData > ;
129132 onLike ?: LikeEventHandler < TContextData > ;
@@ -667,10 +670,52 @@ export class BotImpl<TContextData> implements Bot<TContextData> {
667670 if (
668671 message . visibility === "public" || message . visibility === "unlisted"
669672 ) {
670- await ctx . forwardActivity ( this , "followers" ) ;
673+ await ctx . forwardActivity ( this , "followers" , {
674+ skipIfUnsigned : true ,
675+ preferSharedInbox : true ,
676+ excludeBaseUris : [ new URL ( ctx . origin ) ] ,
677+ } ) ;
671678 }
672679 await this . onReply ( session , message ) ;
673680 }
681+ let quoteUrl : URL | null = null ;
682+ // FIXME: eliminate this duplication
683+ for await ( const tag of object . getTags ( ctx ) ) {
684+ if ( tag instanceof Link ) {
685+ const mediaType = tag . mediaType == null
686+ ? null
687+ : parseMediaType ( tag . mediaType ) ;
688+ if (
689+ tag . rel === "https://misskey-hub.net/ns#_misskey_quote" ||
690+ mediaType ?. [ 0 ] === "application/activity+json" ||
691+ mediaType ?. [ 0 ] === "application/ld+json" &&
692+ mediaType [ 1 ] ?. profile === "https://www.w3.org/ns/activitystreams"
693+ ) {
694+ quoteUrl = tag . href ;
695+ break ;
696+ }
697+ }
698+ }
699+ if ( quoteUrl == null ) quoteUrl = object . quoteUrl ;
700+ const quoteTarget = ctx . parseUri ( quoteUrl ) ;
701+ if (
702+ this . onQuote != null &&
703+ quoteTarget ?. type === "object" &&
704+ // @ts -ignore: quoteTarget.class satisfies (typeof messageClasses)[number]
705+ messageClasses . includes ( quoteTarget . class )
706+ ) {
707+ const message = await getMessage ( ) ;
708+ if (
709+ message . visibility === "public" || message . visibility === "unlisted"
710+ ) {
711+ await ctx . forwardActivity ( this , "followers" , {
712+ skipIfUnsigned : true ,
713+ preferSharedInbox : true ,
714+ excludeBaseUris : [ new URL ( ctx . origin ) ] ,
715+ } ) ;
716+ }
717+ await this . onQuote ( session , message ) ;
718+ }
674719 for await ( const tag of object . getTags ( ctx ) ) {
675720 if (
676721 tag instanceof Mention && tag . href != null && this . onMention != null
0 commit comments