@fedify/botkit 0.4.0-dev.192 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bot-impl.js.map +1 -1
- package/dist/bot-impl.test.js.map +1 -1
- package/dist/bot.js.map +1 -1
- package/dist/bot.test.js.map +1 -1
- package/dist/components/FollowButton.d.ts +2 -2
- package/dist/components/Follower.d.ts +2 -2
- package/dist/components/Follower.js.map +1 -1
- package/dist/components/Layout.js.map +1 -1
- package/dist/components/Message.d.ts +2 -2
- package/dist/components/Message.js.map +1 -1
- package/dist/components/Message.test.js.map +1 -1
- package/dist/deno.js +1 -1
- package/dist/deno.js.map +1 -1
- package/dist/emoji.js.map +1 -1
- package/dist/emoji.test.js.map +1 -1
- package/dist/follow-impl.js.map +1 -1
- package/dist/follow-impl.test.js.map +1 -1
- package/dist/message-impl.js.map +1 -1
- package/dist/message-impl.test.js.map +1 -1
- package/dist/pages.js.map +1 -1
- package/dist/repository.js.map +1 -1
- package/dist/repository.test.js.map +1 -1
- package/dist/session-impl.js.map +1 -1
- package/dist/session-impl.test.js.map +1 -1
- package/dist/text.js.map +1 -1
- package/dist/text.test.js.map +1 -1
- package/package.json +1 -1
package/dist/message-impl.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-impl.js","names":["value: unknown","value: MessageClass","session: SessionImpl<TContextData>","message: Omit<\n Message<T, TContextData>,\n \"delete\" | \"reply\" | \"share\" | \"like\" | \"react\"\n >","text: Text<\"block\", TContextData>","options?:\n | SessionPublishOptions<TContextData>\n | SessionPublishOptionsWithClass<MessageClass, TContextData>","options: MessageShareOptions","RawLike","emoji: Emoji | CustomEmoji | DeferredCustomEmoji<TContextData>","existingMentions: readonly Actor[]","mentionedActors: Actor[]","update: Update | undefined","mentionedActorIds: URL[]","hashtags: Hashtag[]","cachedObjects: Record<string, Object>","promises: Promise<Object | null>[]","updated","mentionedActorIds: Set<string>","raw: T","replyTarget?: Message<MessageClass, TContextData>","quoteTarget?: Message<MessageClass, TContextData>","authorized: boolean","mentions: Actor[]","quoteLinks: Link[]","attachments: Document[]","rt: Link | Object | null","cls: new (values: any) => T","quoteUrl: URL | null","qt: Object | null","toIds: URL[]","ccIds: URL[]","actor: Actor","mentionedActorIds?: Set<string>","tag: Link","params: Record<string, string>"],"sources":["../src/message-impl.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { LanguageString } from \"@fedify/vocab-runtime\";\nimport {\n type Actor,\n Announce,\n Article,\n ChatMessage,\n Create,\n Delete,\n Document,\n type Emoji as CustomEmoji,\n EmojiReact,\n Hashtag,\n isActor,\n Like as RawLike,\n Link,\n Mention,\n Note,\n type Object,\n PUBLIC_COLLECTION,\n Question,\n Tombstone,\n Undo,\n Update,\n} from \"@fedify/vocab\";\nimport { decode } from \"html-entities\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport xss from \"xss\";\nimport type { DeferredCustomEmoji, Emoji } from \"./emoji.ts\";\nimport type {\n AuthorizedMessage,\n AuthorizedSharedMessage,\n Message,\n MessageClass,\n MessageShareOptions,\n MessageVisibility,\n} from \"./message.ts\";\nimport type { AuthorizedLike, AuthorizedReaction } from \"./reaction.ts\";\nimport type { Uuid } from \"./repository.ts\";\nimport type { SessionImpl } from \"./session-impl.ts\";\nimport type {\n SessionPublishOptions,\n SessionPublishOptionsWithClass,\n} from \"./session.ts\";\nimport type { Text } from \"./text.ts\";\n\nexport const messageClasses = [Article, ChatMessage, Note, Question];\n\nexport function isMessageObject(value: unknown): value is MessageClass {\n return messageClasses.some((cls) => value instanceof cls);\n}\n\nexport function getMessageClass(\n value: MessageClass,\n): (typeof Article | typeof ChatMessage | typeof Note | typeof Question) & {\n typeId: URL;\n} {\n return value instanceof Article\n ? Article\n : value instanceof ChatMessage\n ? ChatMessage\n : value instanceof Note\n ? Note\n : Question;\n}\n\nexport class MessageImpl<T extends MessageClass, TContextData>\n implements Message<T, TContextData> {\n readonly session: SessionImpl<TContextData>;\n raw: T;\n readonly id: URL;\n readonly actor: Actor;\n readonly visibility: MessageVisibility;\n readonly language?: Intl.Locale | undefined;\n text: string;\n html: string;\n readonly replyTarget?: Message<MessageClass, TContextData> | undefined;\n readonly quoteTarget?: Message<MessageClass, TContextData> | undefined;\n mentions: readonly Actor[];\n hashtags: readonly Hashtag[];\n readonly attachments: readonly Document[];\n readonly published?: Temporal.Instant;\n updated?: Temporal.Instant;\n\n constructor(\n session: SessionImpl<TContextData>,\n message: Omit<\n Message<T, TContextData>,\n \"delete\" | \"reply\" | \"share\" | \"like\" | \"react\"\n >,\n ) {\n this.session = session;\n this.raw = message.raw;\n this.id = message.id;\n this.actor = message.actor;\n this.visibility = message.visibility;\n this.language = message.language;\n this.text = message.text;\n this.html = message.html;\n this.replyTarget = message.replyTarget;\n this.quoteTarget = message.quoteTarget;\n this.mentions = message.mentions;\n this.hashtags = message.hashtags;\n this.attachments = message.attachments;\n this.published = message.published;\n this.updated = message.updated;\n }\n\n reply(\n text: Text<\"block\", TContextData>,\n options?: SessionPublishOptions<TContextData>,\n ): Promise<AuthorizedMessage<Note, TContextData>>;\n reply<T extends MessageClass>(\n text: Text<\"block\", TContextData>,\n options?: SessionPublishOptionsWithClass<T, TContextData> | undefined,\n ): Promise<AuthorizedMessage<T, TContextData>>;\n reply(\n text: Text<\"block\", TContextData>,\n options?:\n | SessionPublishOptions<TContextData>\n | SessionPublishOptionsWithClass<MessageClass, TContextData>,\n ): Promise<AuthorizedMessage<MessageClass, TContextData>> {\n return this.session.publish(text, {\n visibility: this.visibility === \"unknown\" ? \"direct\" : this.visibility,\n ...options,\n replyTarget: this,\n });\n }\n\n async share(\n options: MessageShareOptions = {},\n ): Promise<AuthorizedSharedMessage<T, TContextData>> {\n const published = new Date();\n const id = uuidv7({ msecs: +published }) as Uuid;\n const visibility = options.visibility ?? this.visibility;\n const originalActor = this.actor.id == null ? [] : [this.actor.id];\n const uri = this.session.context.getObjectUri(Announce, { id });\n const announce = new Announce({\n id: uri,\n actor: this.session.context.getActorUri(this.session.bot.identifier),\n published: published.toTemporalInstant(),\n object: this.id,\n tos: visibility === \"public\"\n ? [PUBLIC_COLLECTION]\n : visibility === \"unlisted\" || visibility === \"followers\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ]\n : [],\n ccs: visibility === \"public\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ...originalActor,\n ]\n : visibility === \"unlisted\"\n ? [PUBLIC_COLLECTION, ...originalActor]\n : originalActor,\n });\n await this.session.bot.repository.addMessage(id, announce);\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n announce,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n announce,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n const actor = announce.actorId?.href === this.session.actorId.href\n ? await this.session.getActor()\n : await announce.getActor(this.session.context);\n if (actor == null) throw new TypeError(\"The actor is required.\");\n return {\n raw: announce,\n id: uri,\n actor,\n visibility,\n original: this,\n unshare: async () => {\n await this.session.bot.repository.removeMessage(id);\n const undo = new Undo({\n id: new URL(\"#delete\", uri),\n actor: this.session.context.getActorUri(\n this.session.bot.identifier,\n ),\n tos: announce.toIds,\n ccs: announce.ccIds,\n object: announce,\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n },\n };\n }\n\n async like(): Promise<AuthorizedLike<TContextData>> {\n const uuid = crypto.randomUUID();\n const actor = this.session.context.getActorUri(this.session.bot.identifier);\n const id = new URL(`#like/${uuid}`, actor);\n const activity = new RawLike({\n id,\n actor,\n object: this.id,\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n return {\n raw: activity,\n id,\n actor: await this.session.getActor(),\n message: this,\n unlike: async () => {\n const undo = new Undo({\n id: new URL(`#unlike/${uuid}`, actor),\n actor,\n object: activity,\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n },\n };\n }\n\n async react(\n emoji: Emoji | CustomEmoji | DeferredCustomEmoji<TContextData>,\n ): Promise<AuthorizedReaction<TContextData>> {\n const uuid = crypto.randomUUID();\n const actor = this.session.context.getActorUri(this.session.bot.identifier);\n const id = new URL(`#react/${uuid}`, actor);\n if (typeof emoji === \"function\") {\n emoji = await emoji(this.session);\n }\n const activity = new EmojiReact({\n id,\n actor,\n object: this.id,\n name: typeof emoji === \"string\" ? emoji : emoji.name,\n tags: typeof emoji === \"string\" ? [] : [emoji],\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n return {\n raw: activity,\n id,\n actor: await this.session.getActor(),\n message: this,\n emoji,\n unreact: async () => {\n const undo = new Undo({\n id: new URL(`#unreact/${uuid}`, actor),\n actor,\n object: activity,\n name: typeof emoji === \"string\" ? emoji : emoji.name,\n tags: typeof emoji === \"string\" ? [] : [emoji],\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n },\n };\n }\n}\n\nexport class AuthorizedMessageImpl<T extends MessageClass, TContextData>\n extends MessageImpl<T, TContextData>\n implements AuthorizedMessage<T, TContextData> {\n async update(text: Text<\"block\", TContextData>): Promise<void> {\n const parsed = this.session.context.parseUri(this.id);\n if (\n parsed?.type !== \"object\" ||\n !messageClasses.some((cls) => parsed.class === cls)\n ) {\n return;\n }\n const { id } = parsed.values;\n let existingMentions: readonly Actor[] = [];\n let mentionedActors: Actor[] = [];\n let update: Update | undefined;\n const updated = await this.session.bot.repository.updateMessage(\n id as Uuid,\n async (create) => {\n if (create instanceof Announce) return;\n const message = await create.getObject(this.session.context);\n if (message == null || !isMessageObject(message)) return;\n let contentHtml = \"\";\n for await (const chunk of text.getHtml(this.session)) {\n contentHtml += chunk;\n }\n const tags = await Array.fromAsync(text.getTags(this.session));\n const mentionedActorIds: URL[] = [];\n const hashtags: Hashtag[] = [];\n for (const tag of tags) {\n if (tag instanceof Mention && tag.href != null) {\n mentionedActorIds.push(tag.href);\n } else if (tag instanceof Hashtag) {\n hashtags.push(tag);\n }\n }\n const cachedObjects: Record<string, Object> = {};\n for (const cachedObject of text.getCachedObjects()) {\n if (cachedObject.id == null) continue;\n cachedObjects[cachedObject.id.href] = cachedObject;\n }\n const documentLoader = await this.session.context.getDocumentLoader(\n this.session.bot,\n );\n const promises: Promise<Object | null>[] = [];\n for (const uri of mentionedActorIds) {\n const cachedObject = cachedObjects[uri.href];\n const promise = cachedObject == null\n ? this.session.context.lookupObject(uri, { documentLoader })\n : Promise.resolve(cachedObject);\n promises.push(promise);\n }\n const objects = await Promise.all(promises);\n mentionedActors = objects.filter(isActor);\n this.html = contentHtml;\n this.text = decode(textXss.process(contentHtml));\n existingMentions = this.mentions;\n this.mentions = mentionedActors;\n this.hashtags = hashtags;\n const updated = Temporal.Now.instant();\n this.updated = updated;\n const newMessage = message.clone({\n contents: this.language == null\n ? [contentHtml]\n : [new LanguageString(contentHtml, this.language), contentHtml],\n tags,\n tos: this.visibility === \"public\"\n ? [PUBLIC_COLLECTION, ...mentionedActorIds]\n : this.visibility === \"unlisted\" || this.visibility === \"followers\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ...mentionedActorIds,\n ]\n : mentionedActorIds,\n ccs: this.visibility === \"public\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ]\n : this.visibility === \"unlisted\"\n ? [PUBLIC_COLLECTION]\n : [],\n updated,\n });\n this.raw = newMessage as T;\n create = create.clone({ object: newMessage, updated });\n const to = create.toIds.map((url) => url.href);\n for (const url of newMessage.toIds) {\n if (!to.includes(url.href)) to.push(url.href);\n }\n const cc = create.ccIds.map((url) => url.href);\n for (const url of newMessage.ccIds) {\n if (!cc.includes(url.href)) cc.push(url.href);\n }\n update = new Update({\n id: new URL(\n `#updated/${updated.toString()}`,\n this.session.context.getObjectUri(Create, { id }),\n ),\n actors: newMessage.attributionIds,\n tos: to.map((url) => new URL(url)),\n ccs: cc.map((url) => new URL(url)),\n object: newMessage,\n updated,\n });\n return create;\n },\n );\n if (!updated || update == null) return;\n const preferSharedInbox = this.visibility === \"public\" ||\n this.visibility === \"unlisted\" || this.visibility === \"followers\";\n const excludeBaseUris = [new URL(this.session.context.origin)];\n if (preferSharedInbox) {\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n update,\n { preferSharedInbox, excludeBaseUris },\n );\n }\n await this.session.context.sendActivity(\n this.session.bot,\n [...existingMentions, ...mentionedActors],\n update,\n { preferSharedInbox, excludeBaseUris },\n );\n if (this.replyTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.replyTarget.actor,\n update,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n if (this.quoteTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.quoteTarget.actor,\n update,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n }\n\n async delete(): Promise<void> {\n const parsed = this.session.context.parseUri(this.id);\n if (\n parsed?.type !== \"object\" ||\n !messageClasses.some((cls) => parsed.class === cls)\n ) {\n return;\n }\n const { id } = parsed.values;\n const create = await this.session.bot.repository.removeMessage(id as Uuid);\n if (create == null) return;\n const message = await create.getObject(this.session.context);\n if (message == null) return;\n const mentionedActorIds: Set<string> = new Set();\n for await (const tag of message.getTags(this.session.context)) {\n if (tag instanceof Mention && tag.href != null) {\n mentionedActorIds.add(tag.href.href);\n }\n }\n const promises: Promise<Object | null>[] = [];\n const documentLoader = await this.session.context.getDocumentLoader(\n this.session.bot,\n );\n for (const uri of mentionedActorIds) {\n promises.push(this.session.context.lookupObject(uri, { documentLoader }));\n }\n const mentionedActors = (await Promise.all(promises)).filter(isActor);\n const activity = new Delete({\n id: new URL(\"#delete\", this.id),\n actor: this.session.context.getActorUri(this.session.bot.identifier),\n tos: create.toIds,\n ccs: create.ccIds,\n object: new Tombstone({\n id: this.id,\n }),\n });\n const excludeBaseUris = [new URL(this.session.context.origin)];\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n activity,\n { preferSharedInbox: true, excludeBaseUris },\n );\n if (mentionedActors.length > 0) {\n await this.session.context.sendActivity(\n this.session.bot,\n mentionedActors,\n activity,\n { preferSharedInbox: true, excludeBaseUris },\n );\n }\n if (this.replyTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.replyTarget.actor,\n activity,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n if (this.quoteTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.quoteTarget.actor,\n activity,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n }\n}\n\n// @ts-ignore: The `xss` module has `getDefaultWhiteList` function.\nconst allowList = xss.getDefaultWhiteList();\n// @ts-ignore: The `xss` module has `FilterXSS` class.\nconst htmlXss = new xss.FilterXSS({\n allowList: {\n ...allowList,\n a: [...allowList.a ?? [], \"class\", \"translate\"],\n },\n});\n// @ts-ignore: The `xss` module has `FilterXSS` class.\nexport const textXss = new xss.FilterXSS({\n allowList: {},\n stripIgnoreTag: true,\n});\n\nexport async function createMessage<T extends MessageClass, TContextData>(\n raw: T,\n session: SessionImpl<TContextData>,\n cachedObjects: Record<string, Object>,\n replyTarget: Message<MessageClass, TContextData> | undefined,\n quote: Message<MessageClass, TContextData> | undefined,\n authorized: true,\n): Promise<AuthorizedMessage<T, TContextData>>;\nexport async function createMessage<T extends MessageClass, TContextData>(\n raw: T,\n session: SessionImpl<TContextData>,\n cachedObjects: Record<string, Object>,\n replyTarget?: Message<MessageClass, TContextData>,\n quote?: Message<MessageClass, TContextData>,\n authorized?: boolean,\n): Promise<Message<T, TContextData>>;\nexport async function createMessage<T extends MessageClass, TContextData>(\n raw: T,\n session: SessionImpl<TContextData>,\n cachedObjects: Record<string, Object>,\n replyTarget?: Message<MessageClass, TContextData>,\n quoteTarget?: Message<MessageClass, TContextData>,\n authorized: boolean = false,\n): Promise<Message<T, TContextData>> {\n if (raw.id == null) throw new TypeError(\"The raw.id is required.\");\n else if (raw.content == null) {\n throw new TypeError(\"The raw.content is required.\");\n }\n const documentLoader = await session.context.getDocumentLoader(session.bot);\n const options = {\n contextLoader: session.context.contextLoader,\n documentLoader,\n suppressError: true,\n };\n const actor = raw.attributionId?.href === session.actorId?.href\n ? await session.getActor()\n : await raw.getAttribution(options);\n if (actor == null) {\n throw new TypeError(\"The raw.attributionId is required.\");\n }\n const content = raw.content.toString();\n const text = textXss.process(content);\n const html = htmlXss.process(content);\n const mentions: Actor[] = [];\n const mentionedActorIds = new Set<string>();\n const hashtags: Hashtag[] = [];\n const quoteLinks: Link[] = [];\n for await (const tag of raw.getTags(options)) {\n if (tag instanceof Mention && tag.href != null) {\n const obj = tag.href.href === session.actorId?.href\n ? await session.getActor()\n : cachedObjects[tag.href.href] == null\n ? await session.context.lookupObject(tag.href, options)\n : cachedObjects[tag.href.href];\n if (isActor(obj)) mentions.push(obj);\n mentionedActorIds.add(tag.href.href);\n } else if (tag instanceof Hashtag) {\n hashtags.push(tag);\n } else if (tag instanceof Link && isQuoteLink(tag)) {\n quoteLinks.push(tag);\n }\n }\n const attachments: Document[] = [];\n for await (const attachment of raw.getAttachments(options)) {\n if (attachment instanceof Document) attachments.push(attachment);\n }\n if (replyTarget == null) {\n let rt: Link | Object | null;\n const parsed = session.context.parseUri(raw.replyTargetId);\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n if (parsed?.type === \"object\" && messageClasses.includes(parsed.class)) {\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n // deno-lint-ignore no-explicit-any\n const cls: new (values: any) => T = parsed.class;\n rt = await session.bot.dispatchMessage(\n cls,\n session.context,\n parsed.values.id,\n );\n } else {\n rt = await raw.getReplyTarget(options);\n }\n if (\n rt instanceof Article || rt instanceof ChatMessage ||\n rt instanceof Note || rt instanceof Question\n ) {\n replyTarget = await createMessage(rt, session, cachedObjects);\n }\n }\n if (quoteTarget == null) {\n let quoteUrl: URL | null = null;\n for (const quoteLink of quoteLinks) {\n if (quoteLink.href == null) continue;\n quoteUrl = quoteLink.href;\n break;\n }\n if (quoteUrl == null) quoteUrl = raw.quoteUrl;\n let qt: Object | null = null;\n const parsed = session.context.parseUri(quoteUrl);\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n if (parsed?.type === \"object\" && messageClasses.includes(parsed.class)) {\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n // deno-lint-ignore no-explicit-any\n const cls: new (values: any) => T = parsed.class;\n qt = await session.bot.dispatchMessage(\n cls,\n session.context,\n parsed.values.id,\n );\n } else if (quoteUrl != null) {\n qt = await session.context.lookupObject(quoteUrl, options);\n }\n if (\n qt instanceof Article || qt instanceof ChatMessage ||\n qt instanceof Note || qt instanceof Question\n ) {\n quoteTarget = await createMessage(qt, session, cachedObjects);\n }\n }\n return new (authorized ? AuthorizedMessageImpl : MessageImpl)(session, {\n raw,\n id: raw.id,\n actor,\n visibility: getMessageVisibility(\n raw.toIds,\n raw.ccIds,\n actor,\n mentionedActorIds,\n ),\n language: raw.content instanceof LanguageString\n ? raw.content.locale\n : undefined,\n text: decode(text),\n html,\n replyTarget,\n quoteTarget,\n mentions,\n hashtags,\n attachments,\n published: raw.published ?? undefined,\n updated: raw.updated ?? undefined,\n });\n}\n\nexport function getMessageVisibility(\n toIds: URL[],\n ccIds: URL[],\n actor: Actor,\n mentionedActorIds?: Set<string>,\n): MessageVisibility {\n const to = toIds.map((url) => url.href);\n const cc = ccIds.map((url) => url.href);\n const recipients = new Set([...to, ...cc]);\n return to.includes(PUBLIC_COLLECTION.href)\n ? \"public\"\n : cc.includes(PUBLIC_COLLECTION.href)\n ? \"unlisted\"\n : actor.followersId != null &&\n (to.includes(actor.followersId.href) ||\n cc.includes(actor.followersId.href))\n ? \"followers\"\n : recipients.size > 0 &&\n recipients.intersection(mentionedActorIds ?? new Set()).size ===\n recipients.size\n ? \"direct\"\n : \"unknown\";\n}\n\nexport function isQuoteLink(tag: Link): boolean {\n if (tag.rel === \"https://misskey-hub.net/ns#_misskey_quote\") return true;\n else if (tag.mediaType == null) return false;\n // FIXME: Properly parse the media type\n const parsed = tag.mediaType.split(\";\");\n const type = parsed[0].trim();\n if (type === \"application/activity+json\") return true;\n const params: Record<string, string> = {};\n for (let i = 1; i < parsed.length; i++) {\n const param = parsed[i].trim().split(\"=\");\n if (param.length === 2) {\n params[param[0]] = param[1].replace(/\"/g, \"\");\n }\n }\n return type === \"application/ld+json\" &&\n params.profile === \"https://www.w3.org/ns/activitystreams\";\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"message-impl.js","names":["value: unknown","value: MessageClass","session: SessionImpl<TContextData>","message: Omit<\n Message<T, TContextData>,\n \"delete\" | \"reply\" | \"share\" | \"like\" | \"react\"\n >","text: Text<\"block\", TContextData>","options?:\n | SessionPublishOptions<TContextData>\n | SessionPublishOptionsWithClass<MessageClass, TContextData>","options: MessageShareOptions","RawLike","emoji: Emoji | CustomEmoji | DeferredCustomEmoji<TContextData>","existingMentions: readonly Actor[]","mentionedActors: Actor[]","update: Update | undefined","mentionedActorIds: URL[]","hashtags: Hashtag[]","cachedObjects: Record<string, Object>","promises: Promise<Object | null>[]","updated","mentionedActorIds: Set<string>","raw: T","replyTarget?: Message<MessageClass, TContextData>","quoteTarget?: Message<MessageClass, TContextData>","authorized: boolean","mentions: Actor[]","quoteLinks: Link[]","attachments: Document[]","rt: Link | Object | null","cls: new (values: any) => T","quoteUrl: URL | null","qt: Object | null","toIds: URL[]","ccIds: URL[]","actor: Actor","mentionedActorIds?: Set<string>","tag: Link","params: Record<string, string>"],"sources":["../src/message-impl.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025–2026 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { LanguageString } from \"@fedify/vocab-runtime\";\nimport {\n type Actor,\n Announce,\n Article,\n ChatMessage,\n Create,\n Delete,\n Document,\n type Emoji as CustomEmoji,\n EmojiReact,\n Hashtag,\n isActor,\n Like as RawLike,\n Link,\n Mention,\n Note,\n type Object,\n PUBLIC_COLLECTION,\n Question,\n Tombstone,\n Undo,\n Update,\n} from \"@fedify/vocab\";\nimport { decode } from \"html-entities\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport xss from \"xss\";\nimport type { DeferredCustomEmoji, Emoji } from \"./emoji.ts\";\nimport type {\n AuthorizedMessage,\n AuthorizedSharedMessage,\n Message,\n MessageClass,\n MessageShareOptions,\n MessageVisibility,\n} from \"./message.ts\";\nimport type { AuthorizedLike, AuthorizedReaction } from \"./reaction.ts\";\nimport type { Uuid } from \"./repository.ts\";\nimport type { SessionImpl } from \"./session-impl.ts\";\nimport type {\n SessionPublishOptions,\n SessionPublishOptionsWithClass,\n} from \"./session.ts\";\nimport type { Text } from \"./text.ts\";\n\nexport const messageClasses = [Article, ChatMessage, Note, Question];\n\nexport function isMessageObject(value: unknown): value is MessageClass {\n return messageClasses.some((cls) => value instanceof cls);\n}\n\nexport function getMessageClass(\n value: MessageClass,\n): (typeof Article | typeof ChatMessage | typeof Note | typeof Question) & {\n typeId: URL;\n} {\n return value instanceof Article\n ? Article\n : value instanceof ChatMessage\n ? ChatMessage\n : value instanceof Note\n ? Note\n : Question;\n}\n\nexport class MessageImpl<T extends MessageClass, TContextData>\n implements Message<T, TContextData> {\n readonly session: SessionImpl<TContextData>;\n raw: T;\n readonly id: URL;\n readonly actor: Actor;\n readonly visibility: MessageVisibility;\n readonly language?: Intl.Locale | undefined;\n text: string;\n html: string;\n readonly replyTarget?: Message<MessageClass, TContextData> | undefined;\n readonly quoteTarget?: Message<MessageClass, TContextData> | undefined;\n mentions: readonly Actor[];\n hashtags: readonly Hashtag[];\n readonly attachments: readonly Document[];\n readonly published?: Temporal.Instant;\n updated?: Temporal.Instant;\n\n constructor(\n session: SessionImpl<TContextData>,\n message: Omit<\n Message<T, TContextData>,\n \"delete\" | \"reply\" | \"share\" | \"like\" | \"react\"\n >,\n ) {\n this.session = session;\n this.raw = message.raw;\n this.id = message.id;\n this.actor = message.actor;\n this.visibility = message.visibility;\n this.language = message.language;\n this.text = message.text;\n this.html = message.html;\n this.replyTarget = message.replyTarget;\n this.quoteTarget = message.quoteTarget;\n this.mentions = message.mentions;\n this.hashtags = message.hashtags;\n this.attachments = message.attachments;\n this.published = message.published;\n this.updated = message.updated;\n }\n\n reply(\n text: Text<\"block\", TContextData>,\n options?: SessionPublishOptions<TContextData>,\n ): Promise<AuthorizedMessage<Note, TContextData>>;\n reply<T extends MessageClass>(\n text: Text<\"block\", TContextData>,\n options?: SessionPublishOptionsWithClass<T, TContextData> | undefined,\n ): Promise<AuthorizedMessage<T, TContextData>>;\n reply(\n text: Text<\"block\", TContextData>,\n options?:\n | SessionPublishOptions<TContextData>\n | SessionPublishOptionsWithClass<MessageClass, TContextData>,\n ): Promise<AuthorizedMessage<MessageClass, TContextData>> {\n return this.session.publish(text, {\n visibility: this.visibility === \"unknown\" ? \"direct\" : this.visibility,\n ...options,\n replyTarget: this,\n });\n }\n\n async share(\n options: MessageShareOptions = {},\n ): Promise<AuthorizedSharedMessage<T, TContextData>> {\n const published = new Date();\n const id = uuidv7({ msecs: +published }) as Uuid;\n const visibility = options.visibility ?? this.visibility;\n const originalActor = this.actor.id == null ? [] : [this.actor.id];\n const uri = this.session.context.getObjectUri(Announce, { id });\n const announce = new Announce({\n id: uri,\n actor: this.session.context.getActorUri(this.session.bot.identifier),\n published: published.toTemporalInstant(),\n object: this.id,\n tos: visibility === \"public\"\n ? [PUBLIC_COLLECTION]\n : visibility === \"unlisted\" || visibility === \"followers\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ]\n : [],\n ccs: visibility === \"public\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ...originalActor,\n ]\n : visibility === \"unlisted\"\n ? [PUBLIC_COLLECTION, ...originalActor]\n : originalActor,\n });\n await this.session.bot.repository.addMessage(id, announce);\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n announce,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n announce,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n const actor = announce.actorId?.href === this.session.actorId.href\n ? await this.session.getActor()\n : await announce.getActor(this.session.context);\n if (actor == null) throw new TypeError(\"The actor is required.\");\n return {\n raw: announce,\n id: uri,\n actor,\n visibility,\n original: this,\n unshare: async () => {\n await this.session.bot.repository.removeMessage(id);\n const undo = new Undo({\n id: new URL(\"#delete\", uri),\n actor: this.session.context.getActorUri(\n this.session.bot.identifier,\n ),\n tos: announce.toIds,\n ccs: announce.ccIds,\n object: announce,\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n },\n };\n }\n\n async like(): Promise<AuthorizedLike<TContextData>> {\n const uuid = crypto.randomUUID();\n const actor = this.session.context.getActorUri(this.session.bot.identifier);\n const id = new URL(`#like/${uuid}`, actor);\n const activity = new RawLike({\n id,\n actor,\n object: this.id,\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n return {\n raw: activity,\n id,\n actor: await this.session.getActor(),\n message: this,\n unlike: async () => {\n const undo = new Undo({\n id: new URL(`#unlike/${uuid}`, actor),\n actor,\n object: activity,\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n },\n };\n }\n\n async react(\n emoji: Emoji | CustomEmoji | DeferredCustomEmoji<TContextData>,\n ): Promise<AuthorizedReaction<TContextData>> {\n const uuid = crypto.randomUUID();\n const actor = this.session.context.getActorUri(this.session.bot.identifier);\n const id = new URL(`#react/${uuid}`, actor);\n if (typeof emoji === \"function\") {\n emoji = await emoji(this.session);\n }\n const activity = new EmojiReact({\n id,\n actor,\n object: this.id,\n name: typeof emoji === \"string\" ? emoji : emoji.name,\n tags: typeof emoji === \"string\" ? [] : [emoji],\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n activity,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n return {\n raw: activity,\n id,\n actor: await this.session.getActor(),\n message: this,\n emoji,\n unreact: async () => {\n const undo = new Undo({\n id: new URL(`#unreact/${uuid}`, actor),\n actor,\n object: activity,\n name: typeof emoji === \"string\" ? emoji : emoji.name,\n tags: typeof emoji === \"string\" ? [] : [emoji],\n });\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n },\n );\n await this.session.context.sendActivity(\n this.session.bot,\n this.actor,\n undo,\n {\n preferSharedInbox: true,\n excludeBaseUris: [new URL(this.session.context.origin)],\n fanout: \"skip\",\n },\n );\n },\n };\n }\n}\n\nexport class AuthorizedMessageImpl<T extends MessageClass, TContextData>\n extends MessageImpl<T, TContextData>\n implements AuthorizedMessage<T, TContextData> {\n async update(text: Text<\"block\", TContextData>): Promise<void> {\n const parsed = this.session.context.parseUri(this.id);\n if (\n parsed?.type !== \"object\" ||\n !messageClasses.some((cls) => parsed.class === cls)\n ) {\n return;\n }\n const { id } = parsed.values;\n let existingMentions: readonly Actor[] = [];\n let mentionedActors: Actor[] = [];\n let update: Update | undefined;\n const updated = await this.session.bot.repository.updateMessage(\n id as Uuid,\n async (create) => {\n if (create instanceof Announce) return;\n const message = await create.getObject(this.session.context);\n if (message == null || !isMessageObject(message)) return;\n let contentHtml = \"\";\n for await (const chunk of text.getHtml(this.session)) {\n contentHtml += chunk;\n }\n const tags = await Array.fromAsync(text.getTags(this.session));\n const mentionedActorIds: URL[] = [];\n const hashtags: Hashtag[] = [];\n for (const tag of tags) {\n if (tag instanceof Mention && tag.href != null) {\n mentionedActorIds.push(tag.href);\n } else if (tag instanceof Hashtag) {\n hashtags.push(tag);\n }\n }\n const cachedObjects: Record<string, Object> = {};\n for (const cachedObject of text.getCachedObjects()) {\n if (cachedObject.id == null) continue;\n cachedObjects[cachedObject.id.href] = cachedObject;\n }\n const documentLoader = await this.session.context.getDocumentLoader(\n this.session.bot,\n );\n const promises: Promise<Object | null>[] = [];\n for (const uri of mentionedActorIds) {\n const cachedObject = cachedObjects[uri.href];\n const promise = cachedObject == null\n ? this.session.context.lookupObject(uri, { documentLoader })\n : Promise.resolve(cachedObject);\n promises.push(promise);\n }\n const objects = await Promise.all(promises);\n mentionedActors = objects.filter(isActor);\n this.html = contentHtml;\n this.text = decode(textXss.process(contentHtml));\n existingMentions = this.mentions;\n this.mentions = mentionedActors;\n this.hashtags = hashtags;\n const updated = Temporal.Now.instant();\n this.updated = updated;\n const newMessage = message.clone({\n contents: this.language == null\n ? [contentHtml]\n : [new LanguageString(contentHtml, this.language), contentHtml],\n tags,\n tos: this.visibility === \"public\"\n ? [PUBLIC_COLLECTION, ...mentionedActorIds]\n : this.visibility === \"unlisted\" || this.visibility === \"followers\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ...mentionedActorIds,\n ]\n : mentionedActorIds,\n ccs: this.visibility === \"public\"\n ? [\n this.session.context.getFollowersUri(this.session.bot.identifier),\n ]\n : this.visibility === \"unlisted\"\n ? [PUBLIC_COLLECTION]\n : [],\n updated,\n });\n this.raw = newMessage as T;\n create = create.clone({ object: newMessage, updated });\n const to = create.toIds.map((url) => url.href);\n for (const url of newMessage.toIds) {\n if (!to.includes(url.href)) to.push(url.href);\n }\n const cc = create.ccIds.map((url) => url.href);\n for (const url of newMessage.ccIds) {\n if (!cc.includes(url.href)) cc.push(url.href);\n }\n update = new Update({\n id: new URL(\n `#updated/${updated.toString()}`,\n this.session.context.getObjectUri(Create, { id }),\n ),\n actors: newMessage.attributionIds,\n tos: to.map((url) => new URL(url)),\n ccs: cc.map((url) => new URL(url)),\n object: newMessage,\n updated,\n });\n return create;\n },\n );\n if (!updated || update == null) return;\n const preferSharedInbox = this.visibility === \"public\" ||\n this.visibility === \"unlisted\" || this.visibility === \"followers\";\n const excludeBaseUris = [new URL(this.session.context.origin)];\n if (preferSharedInbox) {\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n update,\n { preferSharedInbox, excludeBaseUris },\n );\n }\n await this.session.context.sendActivity(\n this.session.bot,\n [...existingMentions, ...mentionedActors],\n update,\n { preferSharedInbox, excludeBaseUris },\n );\n if (this.replyTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.replyTarget.actor,\n update,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n if (this.quoteTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.quoteTarget.actor,\n update,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n }\n\n async delete(): Promise<void> {\n const parsed = this.session.context.parseUri(this.id);\n if (\n parsed?.type !== \"object\" ||\n !messageClasses.some((cls) => parsed.class === cls)\n ) {\n return;\n }\n const { id } = parsed.values;\n const create = await this.session.bot.repository.removeMessage(id as Uuid);\n if (create == null) return;\n const message = await create.getObject(this.session.context);\n if (message == null) return;\n const mentionedActorIds: Set<string> = new Set();\n for await (const tag of message.getTags(this.session.context)) {\n if (tag instanceof Mention && tag.href != null) {\n mentionedActorIds.add(tag.href.href);\n }\n }\n const promises: Promise<Object | null>[] = [];\n const documentLoader = await this.session.context.getDocumentLoader(\n this.session.bot,\n );\n for (const uri of mentionedActorIds) {\n promises.push(this.session.context.lookupObject(uri, { documentLoader }));\n }\n const mentionedActors = (await Promise.all(promises)).filter(isActor);\n const activity = new Delete({\n id: new URL(\"#delete\", this.id),\n actor: this.session.context.getActorUri(this.session.bot.identifier),\n tos: create.toIds,\n ccs: create.ccIds,\n object: new Tombstone({\n id: this.id,\n }),\n });\n const excludeBaseUris = [new URL(this.session.context.origin)];\n await this.session.context.sendActivity(\n this.session.bot,\n \"followers\",\n activity,\n { preferSharedInbox: true, excludeBaseUris },\n );\n if (mentionedActors.length > 0) {\n await this.session.context.sendActivity(\n this.session.bot,\n mentionedActors,\n activity,\n { preferSharedInbox: true, excludeBaseUris },\n );\n }\n if (this.replyTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.replyTarget.actor,\n activity,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n if (this.quoteTarget != null) {\n await this.session.context.sendActivity(\n this.session.bot,\n this.quoteTarget.actor,\n activity,\n { preferSharedInbox: true, excludeBaseUris, fanout: \"skip\" },\n );\n }\n }\n}\n\n// @ts-ignore: The `xss` module has `getDefaultWhiteList` function.\nconst allowList = xss.getDefaultWhiteList();\n// @ts-ignore: The `xss` module has `FilterXSS` class.\nconst htmlXss = new xss.FilterXSS({\n allowList: {\n ...allowList,\n a: [...allowList.a ?? [], \"class\", \"translate\"],\n },\n});\n// @ts-ignore: The `xss` module has `FilterXSS` class.\nexport const textXss = new xss.FilterXSS({\n allowList: {},\n stripIgnoreTag: true,\n});\n\nexport async function createMessage<T extends MessageClass, TContextData>(\n raw: T,\n session: SessionImpl<TContextData>,\n cachedObjects: Record<string, Object>,\n replyTarget: Message<MessageClass, TContextData> | undefined,\n quote: Message<MessageClass, TContextData> | undefined,\n authorized: true,\n): Promise<AuthorizedMessage<T, TContextData>>;\nexport async function createMessage<T extends MessageClass, TContextData>(\n raw: T,\n session: SessionImpl<TContextData>,\n cachedObjects: Record<string, Object>,\n replyTarget?: Message<MessageClass, TContextData>,\n quote?: Message<MessageClass, TContextData>,\n authorized?: boolean,\n): Promise<Message<T, TContextData>>;\nexport async function createMessage<T extends MessageClass, TContextData>(\n raw: T,\n session: SessionImpl<TContextData>,\n cachedObjects: Record<string, Object>,\n replyTarget?: Message<MessageClass, TContextData>,\n quoteTarget?: Message<MessageClass, TContextData>,\n authorized: boolean = false,\n): Promise<Message<T, TContextData>> {\n if (raw.id == null) throw new TypeError(\"The raw.id is required.\");\n else if (raw.content == null) {\n throw new TypeError(\"The raw.content is required.\");\n }\n const documentLoader = await session.context.getDocumentLoader(session.bot);\n const options = {\n contextLoader: session.context.contextLoader,\n documentLoader,\n suppressError: true,\n };\n const actor = raw.attributionId?.href === session.actorId?.href\n ? await session.getActor()\n : await raw.getAttribution(options);\n if (actor == null) {\n throw new TypeError(\"The raw.attributionId is required.\");\n }\n const content = raw.content.toString();\n const text = textXss.process(content);\n const html = htmlXss.process(content);\n const mentions: Actor[] = [];\n const mentionedActorIds = new Set<string>();\n const hashtags: Hashtag[] = [];\n const quoteLinks: Link[] = [];\n for await (const tag of raw.getTags(options)) {\n if (tag instanceof Mention && tag.href != null) {\n const obj = tag.href.href === session.actorId?.href\n ? await session.getActor()\n : cachedObjects[tag.href.href] == null\n ? await session.context.lookupObject(tag.href, options)\n : cachedObjects[tag.href.href];\n if (isActor(obj)) mentions.push(obj);\n mentionedActorIds.add(tag.href.href);\n } else if (tag instanceof Hashtag) {\n hashtags.push(tag);\n } else if (tag instanceof Link && isQuoteLink(tag)) {\n quoteLinks.push(tag);\n }\n }\n const attachments: Document[] = [];\n for await (const attachment of raw.getAttachments(options)) {\n if (attachment instanceof Document) attachments.push(attachment);\n }\n if (replyTarget == null) {\n let rt: Link | Object | null;\n const parsed = session.context.parseUri(raw.replyTargetId);\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n if (parsed?.type === \"object\" && messageClasses.includes(parsed.class)) {\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n // deno-lint-ignore no-explicit-any\n const cls: new (values: any) => T = parsed.class;\n rt = await session.bot.dispatchMessage(\n cls,\n session.context,\n parsed.values.id,\n );\n } else {\n rt = await raw.getReplyTarget(options);\n }\n if (\n rt instanceof Article || rt instanceof ChatMessage ||\n rt instanceof Note || rt instanceof Question\n ) {\n replyTarget = await createMessage(rt, session, cachedObjects);\n }\n }\n if (quoteTarget == null) {\n let quoteUrl: URL | null = null;\n for (const quoteLink of quoteLinks) {\n if (quoteLink.href == null) continue;\n quoteUrl = quoteLink.href;\n break;\n }\n if (quoteUrl == null) quoteUrl = raw.quoteUrl;\n let qt: Object | null = null;\n const parsed = session.context.parseUri(quoteUrl);\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n if (parsed?.type === \"object\" && messageClasses.includes(parsed.class)) {\n // @ts-ignore: The `class` property satisfies the `MessageClass` type.\n // deno-lint-ignore no-explicit-any\n const cls: new (values: any) => T = parsed.class;\n qt = await session.bot.dispatchMessage(\n cls,\n session.context,\n parsed.values.id,\n );\n } else if (quoteUrl != null) {\n qt = await session.context.lookupObject(quoteUrl, options);\n }\n if (\n qt instanceof Article || qt instanceof ChatMessage ||\n qt instanceof Note || qt instanceof Question\n ) {\n quoteTarget = await createMessage(qt, session, cachedObjects);\n }\n }\n return new (authorized ? AuthorizedMessageImpl : MessageImpl)(session, {\n raw,\n id: raw.id,\n actor,\n visibility: getMessageVisibility(\n raw.toIds,\n raw.ccIds,\n actor,\n mentionedActorIds,\n ),\n language: raw.content instanceof LanguageString\n ? raw.content.locale\n : undefined,\n text: decode(text),\n html,\n replyTarget,\n quoteTarget,\n mentions,\n hashtags,\n attachments,\n published: raw.published ?? undefined,\n updated: raw.updated ?? undefined,\n });\n}\n\nexport function getMessageVisibility(\n toIds: URL[],\n ccIds: URL[],\n actor: Actor,\n mentionedActorIds?: Set<string>,\n): MessageVisibility {\n const to = toIds.map((url) => url.href);\n const cc = ccIds.map((url) => url.href);\n const recipients = new Set([...to, ...cc]);\n return to.includes(PUBLIC_COLLECTION.href)\n ? \"public\"\n : cc.includes(PUBLIC_COLLECTION.href)\n ? \"unlisted\"\n : actor.followersId != null &&\n (to.includes(actor.followersId.href) ||\n cc.includes(actor.followersId.href))\n ? \"followers\"\n : recipients.size > 0 &&\n recipients.intersection(mentionedActorIds ?? new Set()).size ===\n recipients.size\n ? \"direct\"\n : \"unknown\";\n}\n\nexport function isQuoteLink(tag: Link): boolean {\n if (tag.rel === \"https://misskey-hub.net/ns#_misskey_quote\") return true;\n else if (tag.mediaType == null) return false;\n // FIXME: Properly parse the media type\n const parsed = tag.mediaType.split(\";\");\n const type = parsed[0].trim();\n if (type === \"application/activity+json\") return true;\n const params: Record<string, string> = {};\n for (let i = 1; i < parsed.length; i++) {\n const param = parsed[i].trim().split(\"=\");\n if (param.length === 2) {\n params[param[0]] = param[1].replace(/\"/g, \"\");\n }\n }\n return type === \"application/ld+json\" &&\n params.profile === \"https://www.w3.org/ns/activitystreams\";\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-impl.test.js","names":["RawLike","recipients","activity","CustomEmoji","deferredEmoji: DeferredCustomEmoji<void>"],"sources":["../src/message-impl.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport {\n Announce,\n Article,\n ChatMessage,\n Create,\n Delete,\n Emoji as CustomEmoji,\n EmojiReact,\n Hashtag,\n Image,\n Like as RawLike,\n Mention,\n Note,\n Person,\n PUBLIC_COLLECTION,\n Question,\n Tombstone,\n Undo,\n Update,\n} from \"@fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport { type DeferredCustomEmoji, emoji } from \"./emoji.ts\";\nimport {\n createMessage,\n getMessageClass,\n getMessageVisibility,\n isMessageObject,\n} from \"./message-impl.ts\";\nimport { MemoryRepository } from \"./repository.ts\";\nimport { createMockContext } from \"./session-impl.test.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\nimport { text } from \"./text.ts\";\n\ntest(\"isMessageObject()\", () => {\n assert.ok(isMessageObject(new Article({})));\n assert.ok(isMessageObject(new ChatMessage({})));\n assert.ok(isMessageObject(new Note({})));\n assert.ok(isMessageObject(new Question({})));\n assert.ok(!isMessageObject(new Person({})));\n});\n\ntest(\"getMessageClass()\", () => {\n assert.deepStrictEqual(\n getMessageClass(new Article({})),\n Article,\n );\n assert.deepStrictEqual(\n getMessageClass(new ChatMessage({})),\n ChatMessage,\n );\n assert.deepStrictEqual(\n getMessageClass(new Note({})),\n Note,\n );\n assert.deepStrictEqual(\n getMessageClass(new Question({})),\n Question,\n );\n});\n\ntest(\"createMessage()\", async () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const session = bot.getSession(\"https://example.com\", undefined);\n await assert.rejects(\n () => createMessage<Note, void>(new Note({}), session, {}),\n TypeError,\n \"The raw.id is required.\",\n );\n await assert.rejects(\n () =>\n createMessage<Note, void>(\n new Note({ id: new URL(\"https://example.com/notes/1\") }),\n session,\n {},\n ),\n TypeError,\n \"The raw.content is required.\",\n );\n await assert.rejects(\n () =>\n createMessage<Note, void>(\n new Note({\n id: new URL(\"https://example.com/notes/1\"),\n content: \"<p>Hello, world!</p>\",\n }),\n session,\n {},\n ),\n TypeError,\n \"The raw.attributionId is required.\",\n );\n\n const publicNote = new Note({\n id: new URL(\"https://example.com/notes/1\"),\n content: \"<p>#Hello, <em>world</em>!</p>\",\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n tags: [\n new Mention({\n name: \"@bot\",\n href: new URL(\"https://example.com/ap/actor/bot\"),\n }),\n new Hashtag({\n name: \"#Hello\",\n href: new URL(\"https://example.com/tags/hello\"),\n }),\n ],\n });\n const publicMessage = await createMessage<Note, void>(\n publicNote,\n session,\n {},\n );\n assert.deepStrictEqual(publicMessage.raw, publicNote);\n assert.deepStrictEqual(publicMessage.id, publicNote.id);\n assert.deepStrictEqual(publicMessage.actor, await session.getActor());\n assert.deepStrictEqual(publicMessage.visibility, \"public\");\n assert.deepStrictEqual(publicMessage.language, undefined);\n assert.deepStrictEqual(publicMessage.text, \"#Hello, world!\");\n assert.deepStrictEqual(publicMessage.html, \"<p>#Hello, <em>world</em>!</p>\");\n assert.deepStrictEqual(publicMessage.replyTarget, undefined);\n assert.deepStrictEqual(publicMessage.mentions, [await session.getActor()]);\n assert.deepStrictEqual(publicMessage.hashtags, [\n new Hashtag({\n name: \"#Hello\",\n href: new URL(\"https://example.com/tags/hello\"),\n }),\n ]);\n assert.deepStrictEqual(publicMessage.attachments, []);\n assert.deepStrictEqual(publicMessage.published, undefined);\n assert.deepStrictEqual(publicMessage.updated, undefined);\n\n const unlistedNote = publicNote.clone({\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const unlistedMessage = await createMessage<Note, void>(\n unlistedNote,\n session,\n {},\n );\n assert.deepStrictEqual(unlistedMessage.visibility, \"unlisted\");\n\n const followersNote = publicNote.clone({\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n ccs: [],\n });\n const followersMessage = await createMessage<Note, void>(\n followersNote,\n session,\n {},\n );\n assert.deepStrictEqual(followersMessage.visibility, \"followers\");\n\n const direct = publicNote.clone({\n to: new URL(\"https://example.com/ap/actor/bot\"),\n ccs: [],\n });\n const directMessage = await createMessage<Note, void>(direct, session, {});\n assert.deepStrictEqual(directMessage.visibility, \"direct\");\n\n const unknown = publicNote.clone({\n tos: [],\n ccs: [],\n });\n const unknownMessage = await createMessage<Note, void>(unknown, session, {});\n assert.deepStrictEqual(unknownMessage.visibility, \"unknown\");\n});\n\ntest(\"AuthorizedMessageImpl.delete()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const note = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n });\n const msg = await createMessage<Note, void>(\n note,\n session,\n {},\n undefined,\n undefined,\n true,\n );\n await repository.addMessage(\n \"c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n new Create({\n id: new URL(\n \"https://example.com/ap/create/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: note,\n }),\n );\n await msg.delete();\n assert.deepStrictEqual(await repository.countMessages(), 0);\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Delete);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(activity.ccIds, [ctx.getFollowersUri(bot.identifier)]);\n const tombstone = await activity.getObject();\n assert.ok(tombstone instanceof Tombstone);\n assert.deepStrictEqual(tombstone.id, note.id);\n});\n\ntest(\"MessageImpl.reply()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: new URL(\"https://example.com/ap/actor/john/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const originalMsg = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n const reply = await originalMsg.reply(text`Hello, John!`);\n assert.deepStrictEqual(await repository.countMessages(), 1);\n const [create] = await Array.fromAsync(repository.getMessages());\n assert.ok(create != null);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Create);\n assert.deepStrictEqual(\n await activity.toJsonLd({ format: \"compact\" }),\n await create.toJsonLd({ format: \"compact\" }),\n );\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [originalMsg.actor]);\n assert.ok(activity2 instanceof Create);\n assert.deepStrictEqual(\n await activity2.toJsonLd({ format: \"compact\" }),\n await create.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(\n await reply.raw.toJsonLd({ format: \"compact\" }),\n await (await create.getObject())?.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(reply.actor, await session.getActor());\n assert.deepStrictEqual(reply.replyTarget, originalMsg);\n assert.deepStrictEqual(reply.visibility, \"unlisted\");\n});\n\ntest(\"MessageImpl.share()\", async (t) => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: new URL(\"https://example.com/ap/actor/john/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const originalMsg = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n const sharedMsg = await originalMsg.share();\n\n await t.test(\"share()\", async () => {\n assert.deepStrictEqual(await repository.countMessages(), 1);\n const [announce] = await Array.fromAsync(repository.getMessages());\n assert.ok(announce != null);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Announce);\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(\n await activity.toJsonLd({ format: \"compact\" }),\n await announce.toJsonLd({ format: \"compact\" }),\n );\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [originalMsg.actor]);\n assert.ok(activity2 instanceof Announce);\n assert.deepStrictEqual(activity2.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity2.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(\n await activity2.toJsonLd({ format: \"compact\" }),\n await announce.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(\n await sharedMsg.raw.toJsonLd({ format: \"compact\" }),\n await announce.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(sharedMsg.actor, await session.getActor());\n assert.deepStrictEqual(sharedMsg.visibility, \"unlisted\");\n assert.deepStrictEqual(sharedMsg.original, originalMsg);\n });\n\n await t.test(\"unshare()\", async () => {\n ctx.sentActivities = [];\n\n await sharedMsg.unshare();\n assert.deepStrictEqual(await repository.countMessages(), 0);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Undo);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(activity.objectId, sharedMsg.id);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [originalMsg.actor]);\n assert.ok(activity2 instanceof Undo);\n assert.deepStrictEqual(activity2.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity2.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity2.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(activity2.objectId, sharedMsg.id);\n });\n});\n\ntest(\"MessageImpl.like()\", async (t) => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: new URL(\"https://example.com/ap/actor/john/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const message = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n const like = await message.like();\n\n await t.test(\"like()\", async () => {\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof RawLike);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.objectId, message.id);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [message.actor]);\n assert.ok(activity2 instanceof RawLike);\n assert.deepStrictEqual(activity2, activity);\n assert.deepStrictEqual(like.actor, await session.getActor());\n assert.deepStrictEqual(like.raw, activity);\n assert.deepStrictEqual(like.id, activity.id);\n assert.deepStrictEqual(like.message, message);\n });\n\n await t.test(\"unlike()\", async () => {\n ctx.sentActivities = [];\n\n await like.unlike();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Undo);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n const object = await activity.getObject();\n assert.ok(object instanceof RawLike);\n assert.deepStrictEqual(object.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(object.objectId, message.id);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [message.actor]);\n assert.ok(activity2 instanceof Undo);\n assert.deepStrictEqual(activity2, activity);\n });\n});\n\ntest(\"AuthorizedMessage.update()\", async (t) => {\n const actorA = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const actorB = new Person({\n id: new URL(\"https://example.com/ap/actor/jane\"),\n preferredUsername: \"jane\",\n });\n\n for (\n const visibility of [\"public\", \"unlisted\", \"followers\", \"direct\"] as const\n ) {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n await t.test(visibility, async () => {\n const msg = await session.publish(text`Hello, ${actorA}`, { visibility });\n assert.deepStrictEqual(await repository.countMessages(), 1);\n const originalRaw = msg.raw;\n ctx.sentActivities = [];\n const before = Temporal.Now.instant();\n await msg.update(text`Hello, ${actorB}`);\n const after = Temporal.Now.instant();\n assert.deepStrictEqual(msg.text, \"Hello, @jane@example.com\");\n assert.deepStrictEqual(\n msg.html,\n '<p>Hello, <a href=\"https://example.com/ap/actor/jane\" ' +\n 'translate=\"no\" class=\"h-card u-url mention\" target=\"_blank\">' +\n \"@<span>jane@example.com</span></a></p>\",\n );\n assert.deepStrictEqual(msg.mentions.length, 1);\n assert.deepStrictEqual(msg.mentions[0].id, actorB.id);\n assert.deepStrictEqual(msg.hashtags, []);\n assert.ok(msg.updated != null);\n assert.ok(msg.updated.epochNanoseconds >= before.epochNanoseconds);\n assert.ok(msg.updated.epochNanoseconds <= after.epochNanoseconds);\n assert.deepStrictEqual(msg.raw.content, msg.html);\n if (visibility === \"public\") {\n assert.deepStrictEqual(msg.raw.toIds, [PUBLIC_COLLECTION, actorB.id]);\n assert.deepStrictEqual(msg.raw.ccIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n } else if (visibility === \"unlisted\") {\n assert.deepStrictEqual(msg.raw.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorB.id,\n ]);\n assert.deepStrictEqual(msg.raw.ccIds, [PUBLIC_COLLECTION]);\n } else if (visibility === \"followers\") {\n assert.deepStrictEqual(msg.raw.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorB.id,\n ]);\n assert.deepStrictEqual(msg.raw.ccIds, []);\n } else {\n assert.deepStrictEqual(msg.raw.toIds, [actorB.id]);\n assert.deepStrictEqual(msg.raw.ccIds, []);\n }\n const tags = await Array.fromAsync(msg.raw.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.ok(tags[0] instanceof Mention);\n assert.deepStrictEqual(tags[0].name, \"@jane@example.com\");\n assert.deepStrictEqual(tags[0].href, actorB.id);\n assert.deepStrictEqual(msg.raw.published, originalRaw.published);\n assert.deepStrictEqual(msg.raw.updated, msg.updated);\n const [create] = await Array.fromAsync(repository.getMessages());\n assert.deepStrictEqual(\n await (await create.getObject())?.toJsonLd({ format: \"compact\" }),\n await msg.raw.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(\n ctx.sentActivities.length,\n visibility === \"direct\" ? 1 : 2,\n );\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(\n recipients,\n visibility === \"direct\" ? [actorA, actorB] : \"followers\",\n );\n assert.ok(activity instanceof Update);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n if (visibility === \"public\") {\n assert.deepStrictEqual(activity.toIds, [\n PUBLIC_COLLECTION,\n actorA.id,\n actorB.id,\n ]);\n assert.deepStrictEqual(activity.ccIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n } else if (visibility === \"unlisted\") {\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorA.id,\n actorB.id,\n ]);\n assert.deepStrictEqual(activity.ccIds, [PUBLIC_COLLECTION]);\n } else if (visibility === \"followers\") {\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorA.id,\n actorB.id,\n ]);\n assert.deepStrictEqual(activity.ccIds, []);\n } else {\n assert.deepStrictEqual(activity.toIds, [actorA.id, actorB.id]);\n assert.deepStrictEqual(activity.ccIds, []);\n }\n assert.deepStrictEqual(await activity.getObject(), msg.raw);\n assert.deepStrictEqual(activity.updated, msg.updated);\n if (visibility !== \"direct\") {\n const { recipients, activity } = ctx.sentActivities[1];\n assert.deepStrictEqual(recipients, [actorA, actorB]);\n assert.ok(activity instanceof Update);\n assert.deepStrictEqual(\n activity.actorId,\n ctx.getActorUri(bot.identifier),\n );\n assert.deepStrictEqual(await activity.getObject(), msg.raw);\n assert.deepStrictEqual(activity.updated, msg.updated);\n }\n });\n }\n});\n\ntest(\"getMessageVisibility()\", () => {\n assert.deepStrictEqual(\n getMessageVisibility([PUBLIC_COLLECTION], [], new Person({})),\n \"public\",\n );\n assert.deepStrictEqual(\n getMessageVisibility([], [PUBLIC_COLLECTION], new Person({})),\n \"unlisted\",\n );\n assert.deepStrictEqual(\n getMessageVisibility(\n [],\n [new URL(\"https://example.com/followers\")],\n new Person({\n followers: new URL(\"https://example.com/followers\"),\n }),\n ),\n \"followers\",\n );\n assert.deepStrictEqual(\n getMessageVisibility(\n [new URL(\"https://example.com/followers\")],\n [],\n new Person({\n followers: new URL(\"https://example.com/followers\"),\n }),\n ),\n \"followers\",\n );\n assert.deepStrictEqual(\n getMessageVisibility(\n [new URL(\"https://example.com/actor\")],\n [],\n new Person({}),\n new Set([\"https://example.com/actor\"]),\n ),\n \"direct\",\n );\n assert.deepStrictEqual(\n getMessageVisibility([], [], new Person({})),\n \"unknown\",\n );\n});\n\ntest(\"MessageImpl.react()\", async (t) => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/react-test-note\",\n ),\n content: \"<p>React to this!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: PUBLIC_COLLECTION,\n });\n const message = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n\n await t.test(\"react() with string emoji\", async () => {\n ctx.sentActivities = []; // Clear previous activities\n const reaction = await message.react(emoji`👍`);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof EmojiReact);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.objectId, message.id);\n assert.deepStrictEqual(activity.name, \"👍\");\n assert.deepStrictEqual(await Array.fromAsync(activity.getTags()), []);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [message.actor]);\n assert.ok(activity2 instanceof EmojiReact);\n assert.deepStrictEqual(activity2, activity);\n assert.deepStrictEqual(reaction.actor, await session.getActor());\n assert.deepStrictEqual(reaction.raw, activity);\n assert.deepStrictEqual(reaction.id, activity.id);\n assert.deepStrictEqual(reaction.message, message);\n assert.deepStrictEqual(reaction.emoji, emoji`👍`);\n\n // Test unreact\n ctx.sentActivities = [];\n await reaction.unreact();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients: urRecipients, activity: urActivity } =\n ctx.sentActivities[0];\n assert.deepStrictEqual(urRecipients, \"followers\");\n assert.ok(urActivity instanceof Undo);\n assert.deepStrictEqual(urActivity.actorId, ctx.getActorUri(bot.identifier));\n const urObject = await urActivity.getObject();\n assert.ok(urObject instanceof EmojiReact);\n assert.deepStrictEqual(urObject.id, reaction.id);\n const { recipients: urRecipients2, activity: urActivity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(urRecipients2, [message.actor]);\n assert.ok(urActivity2 instanceof Undo);\n assert.deepStrictEqual(urActivity2, urActivity);\n });\n\n await t.test(\"react() with CustomEmoji\", async () => {\n ctx.sentActivities = [];\n const customEmoji = new CustomEmoji({\n id: new URL(\"https://example.com/emojis/custom\"),\n name: \":custom:\",\n icon: new Image({\n url: new URL(\"https://example.com/emojis/custom.png\"),\n }),\n });\n const reaction = await message.react(customEmoji);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity } = ctx.sentActivities[0];\n assert.ok(activity instanceof EmojiReact);\n assert.deepStrictEqual(activity.name, \":custom:\");\n const tags = await Array.fromAsync(activity.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.deepStrictEqual(tags[0], customEmoji);\n assert.deepStrictEqual(reaction.emoji, customEmoji);\n\n // Test unreact\n ctx.sentActivities = [];\n await reaction.unreact();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity: urActivity } = ctx.sentActivities[0];\n assert.ok(urActivity instanceof Undo);\n const urObject = await urActivity.getObject();\n assert.ok(urObject instanceof EmojiReact);\n assert.deepStrictEqual(urObject.id, reaction.id);\n const urTags = await Array.fromAsync(urActivity.getTags());\n assert.deepStrictEqual(urTags.length, 1);\n assert.deepStrictEqual(urTags[0], customEmoji);\n });\n\n await t.test(\"react() with DeferredCustomEmoji\", async () => {\n ctx.sentActivities = [];\n const deferredEmoji: DeferredCustomEmoji<void> = (sessionParam) => {\n assert.deepStrictEqual(sessionParam, session); // Ensure correct session is passed\n return new CustomEmoji({\n id: new URL(\"https://example.com/emojis/deferred\"),\n name: \":deferred:\",\n icon: new Image({\n url: new URL(\"https://example.com/emojis/deferred.png\"),\n }),\n });\n };\n const reaction = await message.react(deferredEmoji);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity } = ctx.sentActivities[0];\n assert.ok(activity instanceof EmojiReact);\n assert.deepStrictEqual(activity.name, \":deferred:\");\n const tags = await Array.fromAsync(activity.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.ok(tags[0] instanceof CustomEmoji);\n assert.deepStrictEqual(\n tags[0].id?.href,\n \"https://example.com/emojis/deferred\",\n );\n assert.deepStrictEqual(reaction.emoji, tags[0]);\n\n // Test unreact\n ctx.sentActivities = [];\n await reaction.unreact();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity: urActivity } = ctx.sentActivities[0];\n assert.ok(urActivity instanceof Undo);\n const urObject = await urActivity.getObject();\n assert.ok(urObject instanceof EmojiReact);\n assert.deepStrictEqual(urObject.id, reaction.id);\n const urTags = await Array.fromAsync(urActivity.getTags());\n assert.deepStrictEqual(urTags.length, 1);\n assert.deepStrictEqual(urTags[0], tags[0]); // Should be the resolved CustomEmoji\n });\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"message-impl.test.js","names":["RawLike","recipients","activity","CustomEmoji","deferredEmoji: DeferredCustomEmoji<void>"],"sources":["../src/message-impl.test.ts"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025–2026 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\nimport { MemoryKvStore } from \"@fedify/fedify/federation\";\nimport {\n Announce,\n Article,\n ChatMessage,\n Create,\n Delete,\n Emoji as CustomEmoji,\n EmojiReact,\n Hashtag,\n Image,\n Like as RawLike,\n Mention,\n Note,\n Person,\n PUBLIC_COLLECTION,\n Question,\n Tombstone,\n Undo,\n Update,\n} from \"@fedify/vocab\";\nimport assert from \"node:assert\";\nimport { test } from \"node:test\";\nimport { BotImpl } from \"./bot-impl.ts\";\nimport { type DeferredCustomEmoji, emoji } from \"./emoji.ts\";\nimport {\n createMessage,\n getMessageClass,\n getMessageVisibility,\n isMessageObject,\n} from \"./message-impl.ts\";\nimport { MemoryRepository } from \"./repository.ts\";\nimport { createMockContext } from \"./session-impl.test.ts\";\nimport { SessionImpl } from \"./session-impl.ts\";\nimport { text } from \"./text.ts\";\n\ntest(\"isMessageObject()\", () => {\n assert.ok(isMessageObject(new Article({})));\n assert.ok(isMessageObject(new ChatMessage({})));\n assert.ok(isMessageObject(new Note({})));\n assert.ok(isMessageObject(new Question({})));\n assert.ok(!isMessageObject(new Person({})));\n});\n\ntest(\"getMessageClass()\", () => {\n assert.deepStrictEqual(\n getMessageClass(new Article({})),\n Article,\n );\n assert.deepStrictEqual(\n getMessageClass(new ChatMessage({})),\n ChatMessage,\n );\n assert.deepStrictEqual(\n getMessageClass(new Note({})),\n Note,\n );\n assert.deepStrictEqual(\n getMessageClass(new Question({})),\n Question,\n );\n});\n\ntest(\"createMessage()\", async () => {\n const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: \"bot\" });\n const session = bot.getSession(\"https://example.com\", undefined);\n await assert.rejects(\n () => createMessage<Note, void>(new Note({}), session, {}),\n TypeError,\n \"The raw.id is required.\",\n );\n await assert.rejects(\n () =>\n createMessage<Note, void>(\n new Note({ id: new URL(\"https://example.com/notes/1\") }),\n session,\n {},\n ),\n TypeError,\n \"The raw.content is required.\",\n );\n await assert.rejects(\n () =>\n createMessage<Note, void>(\n new Note({\n id: new URL(\"https://example.com/notes/1\"),\n content: \"<p>Hello, world!</p>\",\n }),\n session,\n {},\n ),\n TypeError,\n \"The raw.attributionId is required.\",\n );\n\n const publicNote = new Note({\n id: new URL(\"https://example.com/notes/1\"),\n content: \"<p>#Hello, <em>world</em>!</p>\",\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n tags: [\n new Mention({\n name: \"@bot\",\n href: new URL(\"https://example.com/ap/actor/bot\"),\n }),\n new Hashtag({\n name: \"#Hello\",\n href: new URL(\"https://example.com/tags/hello\"),\n }),\n ],\n });\n const publicMessage = await createMessage<Note, void>(\n publicNote,\n session,\n {},\n );\n assert.deepStrictEqual(publicMessage.raw, publicNote);\n assert.deepStrictEqual(publicMessage.id, publicNote.id);\n assert.deepStrictEqual(publicMessage.actor, await session.getActor());\n assert.deepStrictEqual(publicMessage.visibility, \"public\");\n assert.deepStrictEqual(publicMessage.language, undefined);\n assert.deepStrictEqual(publicMessage.text, \"#Hello, world!\");\n assert.deepStrictEqual(publicMessage.html, \"<p>#Hello, <em>world</em>!</p>\");\n assert.deepStrictEqual(publicMessage.replyTarget, undefined);\n assert.deepStrictEqual(publicMessage.mentions, [await session.getActor()]);\n assert.deepStrictEqual(publicMessage.hashtags, [\n new Hashtag({\n name: \"#Hello\",\n href: new URL(\"https://example.com/tags/hello\"),\n }),\n ]);\n assert.deepStrictEqual(publicMessage.attachments, []);\n assert.deepStrictEqual(publicMessage.published, undefined);\n assert.deepStrictEqual(publicMessage.updated, undefined);\n\n const unlistedNote = publicNote.clone({\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const unlistedMessage = await createMessage<Note, void>(\n unlistedNote,\n session,\n {},\n );\n assert.deepStrictEqual(unlistedMessage.visibility, \"unlisted\");\n\n const followersNote = publicNote.clone({\n to: new URL(\"https://example.com/ap/actor/bot/followers\"),\n ccs: [],\n });\n const followersMessage = await createMessage<Note, void>(\n followersNote,\n session,\n {},\n );\n assert.deepStrictEqual(followersMessage.visibility, \"followers\");\n\n const direct = publicNote.clone({\n to: new URL(\"https://example.com/ap/actor/bot\"),\n ccs: [],\n });\n const directMessage = await createMessage<Note, void>(direct, session, {});\n assert.deepStrictEqual(directMessage.visibility, \"direct\");\n\n const unknown = publicNote.clone({\n tos: [],\n ccs: [],\n });\n const unknownMessage = await createMessage<Note, void>(unknown, session, {});\n assert.deepStrictEqual(unknownMessage.visibility, \"unknown\");\n});\n\ntest(\"AuthorizedMessageImpl.delete()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const note = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n });\n const msg = await createMessage<Note, void>(\n note,\n session,\n {},\n undefined,\n undefined,\n true,\n );\n await repository.addMessage(\n \"c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n new Create({\n id: new URL(\n \"https://example.com/ap/create/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n actor: new URL(\"https://example.com/ap/actor/bot\"),\n to: PUBLIC_COLLECTION,\n cc: new URL(\"https://example.com/ap/actor/bot/followers\"),\n object: note,\n }),\n );\n await msg.delete();\n assert.deepStrictEqual(await repository.countMessages(), 0);\n assert.deepStrictEqual(ctx.sentActivities.length, 1);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Delete);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [PUBLIC_COLLECTION]);\n assert.deepStrictEqual(activity.ccIds, [ctx.getFollowersUri(bot.identifier)]);\n const tombstone = await activity.getObject();\n assert.ok(tombstone instanceof Tombstone);\n assert.deepStrictEqual(tombstone.id, note.id);\n});\n\ntest(\"MessageImpl.reply()\", async () => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: new URL(\"https://example.com/ap/actor/john/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const originalMsg = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n const reply = await originalMsg.reply(text`Hello, John!`);\n assert.deepStrictEqual(await repository.countMessages(), 1);\n const [create] = await Array.fromAsync(repository.getMessages());\n assert.ok(create != null);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Create);\n assert.deepStrictEqual(\n await activity.toJsonLd({ format: \"compact\" }),\n await create.toJsonLd({ format: \"compact\" }),\n );\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [originalMsg.actor]);\n assert.ok(activity2 instanceof Create);\n assert.deepStrictEqual(\n await activity2.toJsonLd({ format: \"compact\" }),\n await create.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(\n await reply.raw.toJsonLd({ format: \"compact\" }),\n await (await create.getObject())?.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(reply.actor, await session.getActor());\n assert.deepStrictEqual(reply.replyTarget, originalMsg);\n assert.deepStrictEqual(reply.visibility, \"unlisted\");\n});\n\ntest(\"MessageImpl.share()\", async (t) => {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: new URL(\"https://example.com/ap/actor/john/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const originalMsg = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n const sharedMsg = await originalMsg.share();\n\n await t.test(\"share()\", async () => {\n assert.deepStrictEqual(await repository.countMessages(), 1);\n const [announce] = await Array.fromAsync(repository.getMessages());\n assert.ok(announce != null);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Announce);\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(\n await activity.toJsonLd({ format: \"compact\" }),\n await announce.toJsonLd({ format: \"compact\" }),\n );\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [originalMsg.actor]);\n assert.ok(activity2 instanceof Announce);\n assert.deepStrictEqual(activity2.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity2.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(\n await activity2.toJsonLd({ format: \"compact\" }),\n await announce.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(\n await sharedMsg.raw.toJsonLd({ format: \"compact\" }),\n await announce.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(sharedMsg.actor, await session.getActor());\n assert.deepStrictEqual(sharedMsg.visibility, \"unlisted\");\n assert.deepStrictEqual(sharedMsg.original, originalMsg);\n });\n\n await t.test(\"unshare()\", async () => {\n ctx.sentActivities = [];\n\n await sharedMsg.unshare();\n assert.deepStrictEqual(await repository.countMessages(), 0);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Undo);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(activity.objectId, sharedMsg.id);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [originalMsg.actor]);\n assert.ok(activity2 instanceof Undo);\n assert.deepStrictEqual(activity2.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity2.toIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n assert.deepStrictEqual(activity2.ccIds, [\n PUBLIC_COLLECTION,\n originalPost.attributionId,\n ]);\n assert.deepStrictEqual(activity2.objectId, sharedMsg.id);\n });\n});\n\ntest(\"MessageImpl.like()\", async (t) => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788\",\n ),\n content: \"<p>Hello, world!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: new URL(\"https://example.com/ap/actor/john/followers\"),\n cc: PUBLIC_COLLECTION,\n });\n const message = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n const like = await message.like();\n\n await t.test(\"like()\", async () => {\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof RawLike);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.objectId, message.id);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [message.actor]);\n assert.ok(activity2 instanceof RawLike);\n assert.deepStrictEqual(activity2, activity);\n assert.deepStrictEqual(like.actor, await session.getActor());\n assert.deepStrictEqual(like.raw, activity);\n assert.deepStrictEqual(like.id, activity.id);\n assert.deepStrictEqual(like.message, message);\n });\n\n await t.test(\"unlike()\", async () => {\n ctx.sentActivities = [];\n\n await like.unlike();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof Undo);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n const object = await activity.getObject();\n assert.ok(object instanceof RawLike);\n assert.deepStrictEqual(object.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(object.objectId, message.id);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [message.actor]);\n assert.ok(activity2 instanceof Undo);\n assert.deepStrictEqual(activity2, activity);\n });\n});\n\ntest(\"AuthorizedMessage.update()\", async (t) => {\n const actorA = new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n });\n const actorB = new Person({\n id: new URL(\"https://example.com/ap/actor/jane\"),\n preferredUsername: \"jane\",\n });\n\n for (\n const visibility of [\"public\", \"unlisted\", \"followers\", \"direct\"] as const\n ) {\n const repository = new MemoryRepository();\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n repository,\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n\n await t.test(visibility, async () => {\n const msg = await session.publish(text`Hello, ${actorA}`, { visibility });\n assert.deepStrictEqual(await repository.countMessages(), 1);\n const originalRaw = msg.raw;\n ctx.sentActivities = [];\n const before = Temporal.Now.instant();\n await msg.update(text`Hello, ${actorB}`);\n const after = Temporal.Now.instant();\n assert.deepStrictEqual(msg.text, \"Hello, @jane@example.com\");\n assert.deepStrictEqual(\n msg.html,\n '<p>Hello, <a href=\"https://example.com/ap/actor/jane\" ' +\n 'translate=\"no\" class=\"h-card u-url mention\" target=\"_blank\">' +\n \"@<span>jane@example.com</span></a></p>\",\n );\n assert.deepStrictEqual(msg.mentions.length, 1);\n assert.deepStrictEqual(msg.mentions[0].id, actorB.id);\n assert.deepStrictEqual(msg.hashtags, []);\n assert.ok(msg.updated != null);\n assert.ok(msg.updated.epochNanoseconds >= before.epochNanoseconds);\n assert.ok(msg.updated.epochNanoseconds <= after.epochNanoseconds);\n assert.deepStrictEqual(msg.raw.content, msg.html);\n if (visibility === \"public\") {\n assert.deepStrictEqual(msg.raw.toIds, [PUBLIC_COLLECTION, actorB.id]);\n assert.deepStrictEqual(msg.raw.ccIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n } else if (visibility === \"unlisted\") {\n assert.deepStrictEqual(msg.raw.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorB.id,\n ]);\n assert.deepStrictEqual(msg.raw.ccIds, [PUBLIC_COLLECTION]);\n } else if (visibility === \"followers\") {\n assert.deepStrictEqual(msg.raw.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorB.id,\n ]);\n assert.deepStrictEqual(msg.raw.ccIds, []);\n } else {\n assert.deepStrictEqual(msg.raw.toIds, [actorB.id]);\n assert.deepStrictEqual(msg.raw.ccIds, []);\n }\n const tags = await Array.fromAsync(msg.raw.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.ok(tags[0] instanceof Mention);\n assert.deepStrictEqual(tags[0].name, \"@jane@example.com\");\n assert.deepStrictEqual(tags[0].href, actorB.id);\n assert.deepStrictEqual(msg.raw.published, originalRaw.published);\n assert.deepStrictEqual(msg.raw.updated, msg.updated);\n const [create] = await Array.fromAsync(repository.getMessages());\n assert.deepStrictEqual(\n await (await create.getObject())?.toJsonLd({ format: \"compact\" }),\n await msg.raw.toJsonLd({ format: \"compact\" }),\n );\n assert.deepStrictEqual(\n ctx.sentActivities.length,\n visibility === \"direct\" ? 1 : 2,\n );\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(\n recipients,\n visibility === \"direct\" ? [actorA, actorB] : \"followers\",\n );\n assert.ok(activity instanceof Update);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n if (visibility === \"public\") {\n assert.deepStrictEqual(activity.toIds, [\n PUBLIC_COLLECTION,\n actorA.id,\n actorB.id,\n ]);\n assert.deepStrictEqual(activity.ccIds, [\n ctx.getFollowersUri(bot.identifier),\n ]);\n } else if (visibility === \"unlisted\") {\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorA.id,\n actorB.id,\n ]);\n assert.deepStrictEqual(activity.ccIds, [PUBLIC_COLLECTION]);\n } else if (visibility === \"followers\") {\n assert.deepStrictEqual(activity.toIds, [\n ctx.getFollowersUri(bot.identifier),\n actorA.id,\n actorB.id,\n ]);\n assert.deepStrictEqual(activity.ccIds, []);\n } else {\n assert.deepStrictEqual(activity.toIds, [actorA.id, actorB.id]);\n assert.deepStrictEqual(activity.ccIds, []);\n }\n assert.deepStrictEqual(await activity.getObject(), msg.raw);\n assert.deepStrictEqual(activity.updated, msg.updated);\n if (visibility !== \"direct\") {\n const { recipients, activity } = ctx.sentActivities[1];\n assert.deepStrictEqual(recipients, [actorA, actorB]);\n assert.ok(activity instanceof Update);\n assert.deepStrictEqual(\n activity.actorId,\n ctx.getActorUri(bot.identifier),\n );\n assert.deepStrictEqual(await activity.getObject(), msg.raw);\n assert.deepStrictEqual(activity.updated, msg.updated);\n }\n });\n }\n});\n\ntest(\"getMessageVisibility()\", () => {\n assert.deepStrictEqual(\n getMessageVisibility([PUBLIC_COLLECTION], [], new Person({})),\n \"public\",\n );\n assert.deepStrictEqual(\n getMessageVisibility([], [PUBLIC_COLLECTION], new Person({})),\n \"unlisted\",\n );\n assert.deepStrictEqual(\n getMessageVisibility(\n [],\n [new URL(\"https://example.com/followers\")],\n new Person({\n followers: new URL(\"https://example.com/followers\"),\n }),\n ),\n \"followers\",\n );\n assert.deepStrictEqual(\n getMessageVisibility(\n [new URL(\"https://example.com/followers\")],\n [],\n new Person({\n followers: new URL(\"https://example.com/followers\"),\n }),\n ),\n \"followers\",\n );\n assert.deepStrictEqual(\n getMessageVisibility(\n [new URL(\"https://example.com/actor\")],\n [],\n new Person({}),\n new Set([\"https://example.com/actor\"]),\n ),\n \"direct\",\n );\n assert.deepStrictEqual(\n getMessageVisibility([], [], new Person({})),\n \"unknown\",\n );\n});\n\ntest(\"MessageImpl.react()\", async (t) => {\n const bot = new BotImpl<void>({\n kv: new MemoryKvStore(),\n username: \"bot\",\n });\n const ctx = createMockContext(bot, \"https://example.com\");\n const session = new SessionImpl(bot, ctx);\n const originalPost = new Note({\n id: new URL(\n \"https://example.com/ap/note/react-test-note\",\n ),\n content: \"<p>React to this!</p>\",\n attribution: new Person({\n id: new URL(\"https://example.com/ap/actor/john\"),\n preferredUsername: \"john\",\n }),\n to: PUBLIC_COLLECTION,\n });\n const message = await createMessage<Note, void>(\n originalPost,\n session,\n {},\n );\n\n await t.test(\"react() with string emoji\", async () => {\n ctx.sentActivities = []; // Clear previous activities\n const reaction = await message.react(emoji`👍`);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients, activity } = ctx.sentActivities[0];\n assert.deepStrictEqual(recipients, \"followers\");\n assert.ok(activity instanceof EmojiReact);\n assert.deepStrictEqual(activity.actorId, ctx.getActorUri(bot.identifier));\n assert.deepStrictEqual(activity.objectId, message.id);\n assert.deepStrictEqual(activity.name, \"👍\");\n assert.deepStrictEqual(await Array.fromAsync(activity.getTags()), []);\n const { recipients: recipients2, activity: activity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(recipients2, [message.actor]);\n assert.ok(activity2 instanceof EmojiReact);\n assert.deepStrictEqual(activity2, activity);\n assert.deepStrictEqual(reaction.actor, await session.getActor());\n assert.deepStrictEqual(reaction.raw, activity);\n assert.deepStrictEqual(reaction.id, activity.id);\n assert.deepStrictEqual(reaction.message, message);\n assert.deepStrictEqual(reaction.emoji, emoji`👍`);\n\n // Test unreact\n ctx.sentActivities = [];\n await reaction.unreact();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { recipients: urRecipients, activity: urActivity } =\n ctx.sentActivities[0];\n assert.deepStrictEqual(urRecipients, \"followers\");\n assert.ok(urActivity instanceof Undo);\n assert.deepStrictEqual(urActivity.actorId, ctx.getActorUri(bot.identifier));\n const urObject = await urActivity.getObject();\n assert.ok(urObject instanceof EmojiReact);\n assert.deepStrictEqual(urObject.id, reaction.id);\n const { recipients: urRecipients2, activity: urActivity2 } =\n ctx.sentActivities[1];\n assert.deepStrictEqual(urRecipients2, [message.actor]);\n assert.ok(urActivity2 instanceof Undo);\n assert.deepStrictEqual(urActivity2, urActivity);\n });\n\n await t.test(\"react() with CustomEmoji\", async () => {\n ctx.sentActivities = [];\n const customEmoji = new CustomEmoji({\n id: new URL(\"https://example.com/emojis/custom\"),\n name: \":custom:\",\n icon: new Image({\n url: new URL(\"https://example.com/emojis/custom.png\"),\n }),\n });\n const reaction = await message.react(customEmoji);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity } = ctx.sentActivities[0];\n assert.ok(activity instanceof EmojiReact);\n assert.deepStrictEqual(activity.name, \":custom:\");\n const tags = await Array.fromAsync(activity.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.deepStrictEqual(tags[0], customEmoji);\n assert.deepStrictEqual(reaction.emoji, customEmoji);\n\n // Test unreact\n ctx.sentActivities = [];\n await reaction.unreact();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity: urActivity } = ctx.sentActivities[0];\n assert.ok(urActivity instanceof Undo);\n const urObject = await urActivity.getObject();\n assert.ok(urObject instanceof EmojiReact);\n assert.deepStrictEqual(urObject.id, reaction.id);\n const urTags = await Array.fromAsync(urActivity.getTags());\n assert.deepStrictEqual(urTags.length, 1);\n assert.deepStrictEqual(urTags[0], customEmoji);\n });\n\n await t.test(\"react() with DeferredCustomEmoji\", async () => {\n ctx.sentActivities = [];\n const deferredEmoji: DeferredCustomEmoji<void> = (sessionParam) => {\n assert.deepStrictEqual(sessionParam, session); // Ensure correct session is passed\n return new CustomEmoji({\n id: new URL(\"https://example.com/emojis/deferred\"),\n name: \":deferred:\",\n icon: new Image({\n url: new URL(\"https://example.com/emojis/deferred.png\"),\n }),\n });\n };\n const reaction = await message.react(deferredEmoji);\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity } = ctx.sentActivities[0];\n assert.ok(activity instanceof EmojiReact);\n assert.deepStrictEqual(activity.name, \":deferred:\");\n const tags = await Array.fromAsync(activity.getTags());\n assert.deepStrictEqual(tags.length, 1);\n assert.ok(tags[0] instanceof CustomEmoji);\n assert.deepStrictEqual(\n tags[0].id?.href,\n \"https://example.com/emojis/deferred\",\n );\n assert.deepStrictEqual(reaction.emoji, tags[0]);\n\n // Test unreact\n ctx.sentActivities = [];\n await reaction.unreact();\n assert.deepStrictEqual(ctx.sentActivities.length, 2);\n const { activity: urActivity } = ctx.sentActivities[0];\n assert.ok(urActivity instanceof Undo);\n const urObject = await urActivity.getObject();\n assert.ok(urObject instanceof EmojiReact);\n assert.deepStrictEqual(urObject.id, reaction.id);\n const urTags = await Array.fromAsync(urActivity.getTags());\n assert.deepStrictEqual(urTags.length, 1);\n assert.deepStrictEqual(urTags[0], tags[0]); // Should be the resolved CustomEmoji\n });\n});\n"],"mappings":"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"}
|
package/dist/pages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","names":["properties: Record<string, string>","nextLink: URL | undefined","bot: BotImpl<unknown>","ctx: Context<unknown>","options: GetPostsOptions","lastPost: Announce | Create | undefined","nextPost: Object | undefined","post: Create | Announce","context: Context<unknown>","hashtag?: string","hashtag: string"],"sources":["../src/pages.tsx"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\n/** @jsx react-jsx */\n/** @jsxImportSource hono/jsx */\nimport type { Context } from \"@fedify/fedify/federation\";\nimport {\n type Announce,\n type Create,\n getActorHandle,\n Hashtag,\n Image,\n Link,\n type Object,\n PUBLIC_COLLECTION,\n} from \"@fedify/vocab\";\nimport { Hono } from \"hono\";\nimport { decode } from \"html-entities\";\nimport { parseTemplate } from \"url-template\";\nimport type { BotImpl } from \"./bot-impl.ts\";\nimport { FollowButton } from \"./components/FollowButton.tsx\";\nimport { Follower } from \"./components/Follower.tsx\";\nimport { Layout } from \"./components/Layout.tsx\";\nimport { Message } from \"./components/Message.tsx\";\nimport { getMessageClass, isMessageObject, textXss } from \"./message-impl.ts\";\nimport type { MessageClass } from \"./message.ts\";\nimport type { Uuid } from \"./repository.ts\";\n\nexport interface Bindings {\n readonly bot: BotImpl<unknown>;\n readonly contextData: unknown;\n}\n\nexport interface Env {\n readonly Bindings: Bindings;\n}\n\nexport const app = new Hono<Env>();\n\napp.get(\"/\", async (c) => {\n const { bot } = c.env;\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const url = new URL(c.req.url);\n const handle = `@${bot.username}@${url.host}`;\n const icon = bot.icon instanceof Image\n ? bot.icon.url instanceof Link ? bot.icon.url.href : bot.icon.url\n : bot.icon;\n const iconWidth = bot.icon instanceof Image ? bot.icon.width : null;\n const iconHeight = bot.icon instanceof Image ? bot.icon.height : null;\n const image = bot.image instanceof Image\n ? bot.image.url instanceof Link ? bot.image.url.href : bot.image.url\n : bot.image;\n const imageWidth = bot.image instanceof Image ? bot.image.width : null;\n const imageHeight = bot.image instanceof Image ? bot.image.height : null;\n const followersCount = await bot.repository.countFollowers();\n const summaryChunks = bot.summary?.getHtml(session);\n const postsCount = await bot.repository.countMessages();\n const summary = summaryChunks == null\n ? null\n : (await Array.fromAsync(summaryChunks)).join(\"\");\n const properties: Record<string, string> = {};\n for (const name in bot.properties) {\n const value = bot.properties[name];\n const valueHtml = (await Array.fromAsync(value.getHtml(session))).join(\"\");\n properties[name] = valueHtml;\n }\n const offset = c.req.query(\"offset\");\n const { posts: messages, nextPost } = await getPosts(\n bot,\n ctx,\n offset ? { offset: Temporal.Instant.from(offset) } : {},\n );\n const activityLink = ctx.getActorUri(bot.identifier);\n const feedLink = new URL(\"/feed.xml\", url);\n let nextLink: URL | undefined;\n if (nextPost?.published != null) {\n nextLink = new URL(\"/\", url);\n nextLink.searchParams.set(\"offset\", nextPost.published.toString());\n }\n return c.html(\n <Layout\n bot={bot}\n host={url.host}\n activityLink={activityLink}\n feedLink={feedLink}\n >\n <header class=\"container\">\n {image && (\n <img\n src={image.href}\n width={imageWidth ?? undefined}\n height={imageHeight ?? undefined}\n alt={image instanceof Image\n ? image.name?.toString() ?? undefined\n : undefined}\n style=\"width: 100%; margin-bottom: 1em;\"\n />\n )}\n <hgroup>\n {icon && (\n <img\n src={icon.href}\n width={iconWidth ?? undefined}\n height={iconHeight ?? undefined}\n style=\"float: left; margin-right: 1em; height: 72;\"\n />\n )}\n <h1>\n <a href=\"/\">{bot.name ?? bot.username}</a>\n </h1>\n <p>\n <span style=\"user-select: all;\">{handle}</span> ·{\" \"}\n <a\n href=\"/feed.xml\"\n rel=\"alternate\"\n type=\"application/atom+xml\"\n title=\"Atom feed\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={18}\n height={18}\n viewBox=\"0 0 16 16\"\n aria-label=\"Atom feed\"\n >\n <path\n fill=\"currentColor\"\n d=\"M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm1.5 2.5c5.523 0 10 4.477 10 10a1 1 0 1 1-2 0a8 8 0 0 0-8-8a1 1 0 0 1 0-2m0 4a6 6 0 0 1 6 6a1 1 0 1 1-2 0a4 4 0 0 0-4-4a1 1 0 0 1 0-2m.5 7a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3\"\n >\n </path>\n </svg>\n </a>{\" \"}\n ·{\" \"}\n <span>\n <a href=\"/followers\">\n {followersCount === 1\n ? `1 follower`\n : `${followersCount.toLocaleString(\"en\")} followers`}\n </a>\n </span>{\" \"}\n ·{\" \"}\n <span>\n {postsCount === 1\n ? `1 post`\n : `${postsCount.toLocaleString(\"en\")} posts`}\n </span>{\" \"}\n · <FollowButton bot={bot} />\n </p>\n </hgroup>\n {summary &&\n (\n <div\n dangerouslySetInnerHTML={{ __html: summary }}\n />\n )}\n {globalThis.Object.keys(properties).length > 0 && (\n <table>\n <tbody>\n {globalThis.Object.entries(properties).map(([name, value]) => (\n <tr>\n <th scope=\"row\" style=\"width: 1%; white-space: nowrap;\">\n <strong>{name}</strong>\n </th>\n <td\n dangerouslySetInnerHTML={{ __html: value }}\n />\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </header>\n <main class=\"container\">\n {messages.map((message) => (\n <Message message={message} session={session} />\n ))}\n </main>\n <footer class=\"container\">\n <nav style=\"display: block; text-align: end;\">\n {nextLink && (\n <a rel=\"next\" href={nextLink.href}>\n Older posts →\n </a>\n )}\n </nav>\n </footer>\n </Layout>,\n {\n headers: {\n Link:\n `<${activityLink.href}>; rel=\"alternate\"; type=\"application/activity+json\", ` +\n `<${feedLink.href}>; rel=\"alternate\"; type=\"application/atom+xml\"` +\n (nextLink\n ? `, <${nextLink.href}>; rel=\"next\"; type=\"text/html\"`\n : \"\"),\n },\n },\n );\n});\n\napp.get(\"/followers\", async (c) => {\n const { bot } = c.env;\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const followersCount = await bot.repository.countFollowers();\n const followers = await Array.fromAsync(bot.repository.getFollowers());\n\n const url = new URL(c.req.url);\n const activityLink = ctx.getActorUri(bot.identifier);\n const feedLink = new URL(\"/feed.xml\", url);\n\n return c.html(\n <Layout\n bot={bot}\n host={url.host}\n activityLink={activityLink}\n feedLink={feedLink}\n >\n <header class=\"container\">\n <h1>\n <a href=\"/\">←</a>{\" \"}\n {followersCount === 1\n ? `1 follower`\n : `${followersCount.toLocaleString(\"en\")} followers`}\n </h1>\n </header>\n <main class=\"container\">\n {followers.map((follower, index) => (\n <Follower\n key={follower.id?.href ?? index}\n actor={follower}\n session={session}\n />\n ))}\n </main>\n </Layout>,\n );\n});\n\napp.get(\"/tags/:hashtag\", async (c) => {\n const hashtag = c.req.param(\"hashtag\");\n const { bot } = c.env;\n const url = new URL(c.req.url);\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const offset = c.req.query(\"offset\");\n const { posts, nextPost } = await getPosts(bot, ctx, {\n hashtag,\n offset: offset == null ? undefined : Temporal.Instant.from(offset),\n });\n let nextLink: URL | undefined;\n if (nextPost?.published != null) {\n nextLink = new URL(`/tags/${encodeURIComponent(hashtag)}`, url);\n nextLink.searchParams.set(\"offset\", nextPost.published.toString());\n }\n return c.html(\n <Layout bot={bot} host={url.host} title={`#${hashtag}`}>\n <header class=\"container\">\n <h1>#{hashtag}</h1>\n </header>\n <main class=\"container\">\n {posts.map((message) => (\n <Message message={message} session={session} />\n ))}\n </main>\n <footer class=\"container\">\n <nav style=\"display: block; text-align: end;\">\n {nextLink && (\n <a rel=\"next\" href={nextLink.href}>Older posts →</a>\n )}\n </nav>\n </footer>\n </Layout>,\n {\n headers: nextLink == null ? {} : {\n Link: `<${nextLink.href}>; rel=\"next\"; type=\"text/html\"`,\n },\n },\n );\n});\n\napp.get(\"/message/:id\", async (c) => {\n const id = c.req.param(\"id\");\n const { bot } = c.env;\n const url = new URL(c.req.url);\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const post = await bot.repository.getMessage(id as Uuid);\n if (post == null || !isPublic(post)) return c.notFound();\n const message = await post.getObject(ctx);\n if (message == null || !isMessageObject(message)) return c.notFound();\n const activityLink = ctx.getObjectUri<MessageClass>(\n getMessageClass(message),\n { id },\n );\n const feedLink = new URL(\"/feed.xml\", url);\n let title = message.name;\n if (title == null) {\n title = message.summary ?? message.content;\n if (title != null) {\n title = decode(textXss.process(title.toString()));\n }\n }\n return c.html(\n <Layout\n bot={bot}\n host={url.host}\n activityLink={activityLink}\n feedLink={feedLink}\n title={title?.toString() ?? undefined}\n >\n <main class=\"container\">\n <Message message={message} session={session} />\n </main>\n </Layout>,\n {\n headers: {\n Link:\n `<${activityLink.href}>; rel=\"alternate\"; type=\"application/activity+json\", ` +\n `<${feedLink.href}>; rel=\"alternate\"; type=\"application/atom+xml\"`,\n },\n },\n );\n});\n\napp.get(\"/feed.xml\", async (c) => {\n const { bot } = c.env;\n const url = new URL(c.req.url);\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const { posts } = await getPosts(bot, ctx, { window: 30 });\n const botName = bot.name ?? bot.username;\n const canonicalUrl = new URL(\"/feed.xml\", url);\n const profileUrl = new URL(\"/\", url);\n const actorUrl = ctx.getActorUri(bot.identifier);\n c.header(\n \"Link\",\n `<${actorUrl.href}>; rel=\"alternate\"; type=\"application/activity+json\", ` +\n `<${profileUrl.href}>; rel=\"alternate\"; type=\"text/html\"`,\n );\n const response = await c.render(\n <feed xmlns=\"http://www.w3.org/2005/Atom\">\n <id>{canonicalUrl.href}</id>\n <link rel=\"self\" type=\"application/atom+xml\" href={canonicalUrl.href} />\n <link rel=\"alternate\" type=\"text/html\" href={profileUrl.href} />\n <link\n rel=\"alternate\"\n type=\"application/activity+json\"\n href={actorUrl.href}\n />\n <title>{botName} (@{bot.username}@{url.host})</title>\n <author>\n <name>{botName}</name>\n <uri>{profileUrl.href}</uri>\n </author>\n {posts.length > 0 && (\n <updated>\n {(posts[0].updated ?? posts[0].published)?.toString()}\n </updated>\n )}\n {posts.map(async (post) => {\n const activityUrl = post.id;\n if (activityUrl == null) return undefined;\n const permalink =\n (post.url instanceof Link ? post.url.href : post.url) ?? activityUrl;\n const author = post.attributionId?.href === session.actorId?.href\n ? await session.getActor()\n : await post.getAttribution({\n documentLoader: ctx.documentLoader,\n contextLoader: ctx.contextLoader,\n suppressError: true,\n });\n const authorName = author?.name ?? author?.preferredUsername ??\n (author == null ? undefined : await getActorHandle(author));\n const authorUrl =\n (author?.url instanceof Link ? author.url.href : author?.url) ??\n author?.id;\n const updated = post.updated ?? post.published;\n let title = post.name;\n if (title == null) {\n title = post.summary ?? post.content;\n if (title != null) {\n title = decode(textXss.process(title.toString()));\n }\n }\n return (\n <entry>\n <id>{permalink.href}</id>\n <link rel=\"alternate\" type=\"text/html\" href={permalink.href} />\n <link\n rel=\"alternate\"\n type=\"application/activity+json\"\n href={activityUrl.href}\n />\n {authorName &&\n (\n <author>\n <name>{authorName}</name>\n {authorUrl &&\n <uri>{authorUrl.href}</uri>}\n </author>\n )}\n {post.published && (\n <published>{post.published.toString()}</published>\n )}\n {updated && <updated>{updated.toString()}</updated>}\n {title && <title>{title}</title>}\n {post.summary && (\n <summary type=\"html\">{post.summary.toString()}</summary>\n )}\n {post.content && (\n <content type=\"html\">{post.content.toString()}</content>\n )}\n </entry>\n );\n })}\n </feed>,\n );\n response.headers.set(\"Content-Type\", \"application/atom+xml; charset=utf-8\");\n return response;\n});\n\napp.post(\"/follow\", async (c) => {\n const { bot } = c.env;\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const url = new URL(c.req.url);\n\n const formData = await c.req.formData();\n let followerHandle = formData.get(\"handle\")?.toString();\n\n try {\n if (!followerHandle) {\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Error</h1>\n <p>Follower handle is required.</p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 400,\n );\n }\n\n if (followerHandle.startsWith(\"@\")) {\n followerHandle = followerHandle.slice(1);\n }\n\n const webfingerData = await ctx\n .lookupWebFinger(`acct:${followerHandle}`);\n\n if (!webfingerData?.links) {\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Error</h1>\n <p>\n No links found in webfinger data for{\" \"}\n <code>@{followerHandle}</code>.\n </p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 400,\n );\n }\n\n const subscribeLink = webfingerData.links.find(\n (link) => link.rel === \"http://ostatus.org/schema/1.0/subscribe\",\n );\n\n if (subscribeLink?.template) {\n const botActorUri = ctx.getActorUri(bot.identifier);\n const followUrlTemplate = parseTemplate(subscribeLink.template);\n const followUrl = followUrlTemplate.expand({\n uri: botActorUri.href,\n });\n return c.redirect(followUrl);\n }\n\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Error</h1>\n <p>\n No follow link found in WebFinger data for{\" \"}\n <code>@{followerHandle}</code>.\n </p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 400,\n );\n } catch (_error) {\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Internal Server Error</h1>\n <p>\n An internal server error occurred while processing your request.\n </p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 500,\n );\n }\n});\n\ninterface GetPostsOptions {\n readonly hashtag?: string;\n readonly offset?: Temporal.Instant;\n readonly window?: number;\n}\n\nasync function getPosts(\n bot: BotImpl<unknown>,\n ctx: Context<unknown>,\n options: GetPostsOptions = {},\n): Promise<{ posts: MessageClass[]; nextPost?: Object }> {\n const { offset, window = 15 } = options;\n let posts = await Array.fromAsync(\n bot.repository.getMessages({\n order: \"newest\",\n until: offset,\n limit: window * 2,\n }),\n );\n let lastPost: Announce | Create | undefined = posts[posts.length - 1];\n posts = posts.slice(0, posts.length - 1);\n posts = posts.filter(isPublic);\n if (options.hashtag != null) {\n const taggedPosts = [];\n for (const post of posts) {\n if (await hasHashtag(ctx, post, options.hashtag)) {\n taggedPosts.push(post);\n }\n }\n posts = taggedPosts;\n }\n while (lastPost != null && posts.length < window) {\n const limit = (window - posts.length) * 2;\n const until = lastPost.published ??\n (await lastPost.getObject(ctx))?.published ??\n undefined;\n if (until == null) break;\n const nextPosts = bot.repository.getMessages({\n order: \"newest\",\n until,\n limit,\n });\n let i = 0;\n lastPost = undefined;\n for await (const post of nextPosts) {\n if (\n isPublic(post) && await hasHashtag(ctx, post, options.hashtag) &&\n posts.length < window + 1\n ) posts.push(post);\n lastPost = post;\n i++;\n }\n if (i < limit) break;\n }\n const nextPost: Object | undefined = await posts[window]?.getObject(ctx) ??\n undefined;\n posts = posts.slice(0, window);\n const messages = (await Promise.all(posts.map((p) => p.getObject(ctx))))\n .filter(isMessageObject);\n return { posts: messages, nextPost };\n}\n\nfunction isPublic(post: Create | Announce): boolean {\n return post.toIds.some((url) => url.href === PUBLIC_COLLECTION.href) ||\n post.ccIds.some((url) => url.href === PUBLIC_COLLECTION.href);\n}\n\nasync function hasHashtag(\n context: Context<unknown>,\n post: Create | Announce,\n hashtag?: string,\n): Promise<boolean> {\n if (hashtag == null) return true;\n hashtag = normalizeHashtag(hashtag);\n const object = await post.getObject(context);\n if (object == null) return false;\n for await (const tag of object.getTags(context)) {\n if (\n tag instanceof Hashtag && tag.name != null &&\n normalizeHashtag(tag.name.toString()) === hashtag\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction normalizeHashtag(hashtag: string): string {\n return hashtag\n .toLowerCase()\n .trimStart()\n .replace(/^#/, \"\")\n .trim()\n .replace(/\\s+/g, \"\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiDA,MAAa,MAAM,IAAI;AAEvB,IAAI,IAAI,KAAK,OAAO,MAAM;CACxB,MAAM,EAAE,KAAK,GAAG,EAAE;CAClB,MAAM,MAAM,IAAI,WAAW,cAAc,EAAE,IAAI,KAAK,EAAE,IAAI,YAAY;CACtE,MAAM,UAAU,IAAI,WAAW,IAAI;CACnC,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI;CAC1B,MAAM,UAAU,GAAG,IAAI,SAAS,GAAG,IAAI,KAAK;CAC5C,MAAM,OAAO,IAAI,gBAAgB,QAC7B,IAAI,KAAK,eAAe,OAAO,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,MAC5D,IAAI;CACR,MAAM,YAAY,IAAI,gBAAgB,QAAQ,IAAI,KAAK,QAAQ;CAC/D,MAAM,aAAa,IAAI,gBAAgB,QAAQ,IAAI,KAAK,SAAS;CACjE,MAAM,QAAQ,IAAI,iBAAiB,QAC/B,IAAI,MAAM,eAAe,OAAO,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,MAC/D,IAAI;CACR,MAAM,aAAa,IAAI,iBAAiB,QAAQ,IAAI,MAAM,QAAQ;CAClE,MAAM,cAAc,IAAI,iBAAiB,QAAQ,IAAI,MAAM,SAAS;CACpE,MAAM,iBAAiB,MAAM,IAAI,WAAW,gBAAgB;CAC5D,MAAM,gBAAgB,IAAI,SAAS,QAAQ,QAAQ;CACnD,MAAM,aAAa,MAAM,IAAI,WAAW,eAAe;CACvD,MAAM,UAAU,iBAAiB,OAC7B,OACA,CAAC,MAAM,MAAM,UAAU,cAAc,EAAE,KAAK,GAAG;CACnD,MAAMA,aAAqC,CAAE;AAC7C,MAAK,MAAM,QAAQ,IAAI,YAAY;EACjC,MAAM,QAAQ,IAAI,WAAW;EAC7B,MAAM,YAAY,CAAC,MAAM,MAAM,UAAU,MAAM,QAAQ,QAAQ,CAAC,EAAE,KAAK,GAAG;AAC1E,aAAW,QAAQ;CACpB;CACD,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS;CACpC,MAAM,EAAE,OAAO,UAAU,UAAU,GAAG,MAAM,SAC1C,KACA,KACA,SAAS,EAAE,QAAQ,SAAS,QAAQ,KAAK,OAAO,CAAE,IAAG,CAAE,EACxD;CACD,MAAM,eAAe,IAAI,YAAY,IAAI,WAAW;CACpD,MAAM,WAAW,IAAI,IAAI,aAAa;CACtC,IAAIC;AACJ,KAAI,UAAU,aAAa,MAAM;AAC/B,aAAW,IAAI,IAAI,KAAK;AACxB,WAAS,aAAa,IAAI,UAAU,SAAS,UAAU,UAAU,CAAC;CACnE;AACD,QAAO,EAAE,qBACP,KAAC;EACM;EACL,MAAM,IAAI;EACI;EACJ;;mBAEV,KAAC;IAAO,OAAM;;KACX,yBACC,IAAC;MACC,KAAK,MAAM;MACX,OAAO;MACP,QAAQ;MACR,KAAK,iBAAiB,QAClB,MAAM,MAAM,UAAU;MAE1B,OAAM;OACN;qBAEJ,KAAC;MACE,wBACC,IAAC;OACC,KAAK,KAAK;OACV,OAAO;OACP,QAAQ;OACR,OAAM;QACN;sBAEJ,IAAC,kCACC,IAAC;OAAE,MAAK;iBAAK,IAAI,QAAQ,IAAI;QAAa,GACvC;sBACL,KAAC;uBACC,IAAC;QAAK,OAAM;kBAAqB;SAAc;;OAAU;uBACzD,IAAC;QACC,MAAK;QACL,KAAI;QACJ,MAAK;QACL,OAAM;kCAEN,IAAC;SACC,OAAM;SACN,OAAO;SACP,QAAQ;SACR,SAAQ;SACR,cAAW;mCAEX,IAAC;UACC,MAAK;UACL,GAAE;WAEG;UACH;SACJ;OAAC;OAAI;OACA;uBACT,IAAC,oCACC,IAAC;QAAE,MAAK;kBACL,mBAAmB,KACf,eACA,EAAE,eAAe,eAAe,KAAK,CAAC;SACzC,GACC;OAAC;OAAI;OACH;uBACT,IAAC,oBACE,eAAe,KACX,WACA,EAAE,WAAW,eAAe,KAAK,CAAC,UAClC;OAAC;OAAI;uBACH,IAAC,gBAAkB,MAAO;UACjC;SACG;KACR,2BAEG,IAAC,SACC,yBAAyB,EAAE,QAAQ,QAAS,IAC5C;KAEL,WAAW,OAAO,KAAK,WAAW,CAAC,SAAS,qBAC3C,IAAC,qCACC,IAAC,qBACE,WAAW,OAAO,QAAQ,WAAW,CAAC,IAAI,CAAC,CAAC,MAAM,MAAM,qBACvD,KAAC,mCACC,IAAC;MAAG,OAAM;MAAM,OAAM;gCACpB,IAAC,sBAAQ,OAAc;OACpB,kBACL,IAAC,QACC,yBAAyB,EAAE,QAAQ,MAAO,IAC1C,IACC,CACL,GACI,GACF;;KAEH;mBACT,IAAC;IAAK,OAAM;cACT,SAAS,IAAI,CAAC,4BACb,IAAC;KAAiB;KAAkB;MAAW,CAC/C;KACG;mBACP,IAAC;IAAO,OAAM;8BACZ,IAAC;KAAI,OAAM;eACR,4BACC,IAAC;MAAE,KAAI;MAAO,MAAM,SAAS;gBAAM;OAE/B;MAEF;KACC;;GACF,EACT,EACE,SAAS,EACP,OACG,GAAG,aAAa,KAAK,yDAClB,SAAS,KAAK,oDACjB,YACI,KAAK,SAAS,KAAK,mCACpB,IACP,EACF,EACF;AACF,EAAC;AAEF,IAAI,IAAI,cAAc,OAAO,MAAM;CACjC,MAAM,EAAE,KAAK,GAAG,EAAE;CAClB,MAAM,MAAM,IAAI,WAAW,cAAc,EAAE,IAAI,KAAK,EAAE,IAAI,YAAY;CACtE,MAAM,UAAU,IAAI,WAAW,IAAI;CACnC,MAAM,iBAAiB,MAAM,IAAI,WAAW,gBAAgB;CAC5D,MAAM,YAAY,MAAM,MAAM,UAAU,IAAI,WAAW,cAAc,CAAC;CAEtE,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI;CAC1B,MAAM,eAAe,IAAI,YAAY,IAAI,WAAW;CACpD,MAAM,WAAW,IAAI,IAAI,aAAa;AAEtC,QAAO,EAAE,qBACP,KAAC;EACM;EACL,MAAM,IAAI;EACI;EACJ;6BAEV,IAAC;GAAO,OAAM;6BACZ,KAAC;oBACC,IAAC;KAAE,MAAK;eAAI;MAAU;IAAC;IACtB,mBAAmB,KACf,eACA,EAAE,eAAe,eAAe,KAAK,CAAC;OACxC;IACE,kBACT,IAAC;GAAK,OAAM;aACT,UAAU,IAAI,CAAC,UAAU,0BACxB,IAAC;IAEC,OAAO;IACE;MAFJ,SAAS,IAAI,QAAQ,MAG1B,CACF;IACG;GACA,CACV;AACF,EAAC;AAEF,IAAI,IAAI,kBAAkB,OAAO,MAAM;CACrC,MAAM,UAAU,EAAE,IAAI,MAAM,UAAU;CACtC,MAAM,EAAE,KAAK,GAAG,EAAE;CAClB,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI;CAC1B,MAAM,MAAM,IAAI,WAAW,cAAc,EAAE,IAAI,KAAK,EAAE,IAAI,YAAY;CACtE,MAAM,UAAU,IAAI,WAAW,IAAI;CACnC,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS;CACpC,MAAM,EAAE,OAAO,UAAU,GAAG,MAAM,SAAS,KAAK,KAAK;EACnD;EACA,QAAQ,UAAU,gBAAmB,SAAS,QAAQ,KAAK,OAAO;CACnE,EAAC;CACF,IAAIA;AACJ,KAAI,UAAU,aAAa,MAAM;AAC/B,aAAW,IAAI,KAAK,QAAQ,mBAAmB,QAAQ,CAAC,GAAG;AAC3D,WAAS,aAAa,IAAI,UAAU,SAAS,UAAU,UAAU,CAAC;CACnE;AACD,QAAO,EAAE,qBACP,KAAC;EAAY;EAAK,MAAM,IAAI;EAAM,QAAQ,GAAG,QAAQ;;mBACnD,IAAC;IAAO,OAAM;8BACZ,KAAC,mBAAG,KAAE,WAAa;KACZ;mBACT,IAAC;IAAK,OAAM;cACT,MAAM,IAAI,CAAC,4BACV,IAAC;KAAiB;KAAkB;MAAW,CAC/C;KACG;mBACP,IAAC;IAAO,OAAM;8BACZ,IAAC;KAAI,OAAM;eACR,4BACC,IAAC;MAAE,KAAI;MAAO,MAAM,SAAS;gBAAM;OAAsB;MAEvD;KACC;;GACF,EACT,EACE,SAAS,YAAY,OAAO,CAAE,IAAG,EAC/B,OAAO,GAAG,SAAS,KAAK,iCACzB,EACF,EACF;AACF,EAAC;AAEF,IAAI,IAAI,gBAAgB,OAAO,MAAM;CACnC,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;CAC5B,MAAM,EAAE,KAAK,GAAG,EAAE;CAClB,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI;CAC1B,MAAM,MAAM,IAAI,WAAW,cAAc,EAAE,IAAI,KAAK,EAAE,IAAI,YAAY;CACtE,MAAM,UAAU,IAAI,WAAW,IAAI;CACnC,MAAM,OAAO,MAAM,IAAI,WAAW,WAAW,GAAW;AACxD,KAAI,QAAQ,SAAS,SAAS,KAAK,CAAE,QAAO,EAAE,UAAU;CACxD,MAAM,UAAU,MAAM,KAAK,UAAU,IAAI;AACzC,KAAI,WAAW,SAAS,gBAAgB,QAAQ,CAAE,QAAO,EAAE,UAAU;CACrE,MAAM,eAAe,IAAI,aACvB,gBAAgB,QAAQ,EACxB,EAAE,GAAI,EACP;CACD,MAAM,WAAW,IAAI,IAAI,aAAa;CACtC,IAAI,QAAQ,QAAQ;AACpB,KAAI,SAAS,MAAM;AACjB,UAAQ,QAAQ,WAAW,QAAQ;AACnC,MAAI,SAAS,KACX,SAAQ,OAAO,QAAQ,QAAQ,MAAM,UAAU,CAAC,CAAC;CAEpD;AACD,QAAO,EAAE,qBACP,IAAC;EACM;EACL,MAAM,IAAI;EACI;EACJ;EACV,OAAO,OAAO,UAAU;4BAExB,IAAC;GAAK,OAAM;6BACV,IAAC;IAAiB;IAAkB;KAAW;IAC1C;GACA,EACT,EACE,SAAS,EACP,OACG,GAAG,aAAa,KAAK,yDAClB,SAAS,KAAK,iDACrB,EACF,EACF;AACF,EAAC;AAEF,IAAI,IAAI,aAAa,OAAO,MAAM;CAChC,MAAM,EAAE,KAAK,GAAG,EAAE;CAClB,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI;CAC1B,MAAM,MAAM,IAAI,WAAW,cAAc,EAAE,IAAI,KAAK,EAAE,IAAI,YAAY;CACtE,MAAM,UAAU,IAAI,WAAW,IAAI;CACnC,MAAM,EAAE,OAAO,GAAG,MAAM,SAAS,KAAK,KAAK,EAAE,QAAQ,GAAI,EAAC;CAC1D,MAAM,UAAU,IAAI,QAAQ,IAAI;CAChC,MAAM,eAAe,IAAI,IAAI,aAAa;CAC1C,MAAM,aAAa,IAAI,IAAI,KAAK;CAChC,MAAM,WAAW,IAAI,YAAY,IAAI,WAAW;AAChD,GAAE,OACA,SACC,GAAG,SAAS,KAAK,yDACZ,WAAW,KAAK,sCACvB;CACD,MAAM,WAAW,MAAM,EAAE,uBACvB,KAAC;EAAK,OAAM;;mBACV,IAAC,kBAAI,aAAa,OAAU;mBAC5B,IAAC;IAAK,KAAI;IAAO,MAAK;IAAuB,MAAM,aAAa;KAAQ;mBACxE,IAAC;IAAK,KAAI;IAAY,MAAK;IAAY,MAAM,WAAW;KAAQ;mBAChE,IAAC;IACC,KAAI;IACJ,MAAK;IACL,MAAM,SAAS;KACf;mBACF,KAAC;IAAO;IAAQ;IAAI,IAAI;IAAS;IAAE,IAAI;IAAK;OAAS;mBACrD,KAAC,uCACC,IAAC,oBAAM,UAAe,kBACtB,IAAC,mBAAK,WAAW,OAAW,IACrB;GACR,MAAM,SAAS,qBACd,IAAC,uBACE,CAAC,MAAM,GAAG,WAAW,MAAM,GAAG,YAAY,UAAU,GAC7C;GAEX,MAAM,IAAI,OAAO,SAAS;IACzB,MAAM,cAAc,KAAK;AACzB,QAAI,eAAe,KAAM;IACzB,MAAM,aACH,KAAK,eAAe,OAAO,KAAK,IAAI,OAAO,KAAK,QAAQ;IAC3D,MAAM,SAAS,KAAK,eAAe,SAAS,QAAQ,SAAS,OACzD,MAAM,QAAQ,UAAU,GACxB,MAAM,KAAK,eAAe;KAC1B,gBAAgB,IAAI;KACpB,eAAe,IAAI;KACnB,eAAe;IAChB,EAAC;IACJ,MAAM,aAAa,QAAQ,QAAQ,QAAQ,sBACxC,UAAU,gBAAmB,MAAM,eAAe,OAAO;IAC5D,MAAM,aACH,QAAQ,eAAe,OAAO,OAAO,IAAI,OAAO,QAAQ,QACvD,QAAQ;IACZ,MAAM,UAAU,KAAK,WAAW,KAAK;IACrC,IAAI,QAAQ,KAAK;AACjB,QAAI,SAAS,MAAM;AACjB,aAAQ,KAAK,WAAW,KAAK;AAC7B,SAAI,SAAS,KACX,SAAQ,OAAO,QAAQ,QAAQ,MAAM,UAAU,CAAC,CAAC;IAEpD;AACD,2BACE,KAAC;qBACC,IAAC,kBAAI,UAAU,OAAU;qBACzB,IAAC;MAAK,KAAI;MAAY,MAAK;MAAY,MAAM,UAAU;OAAQ;qBAC/D,IAAC;MACC,KAAI;MACJ,MAAK;MACL,MAAM,YAAY;OAClB;KACD,8BAEG,KAAC,uCACC,IAAC,oBAAM,aAAkB,EACxB,6BACC,IAAC,mBAAK,UAAU,OAAW,IACtB;KAEZ,KAAK,6BACJ,IAAC,yBAAW,KAAK,UAAU,UAAU,GAAa;KAEnD,2BAAW,IAAC,uBAAS,QAAQ,UAAU,GAAW;KAClD,yBAAS,IAAC,qBAAO,QAAc;KAC/B,KAAK,2BACJ,IAAC;MAAQ,MAAK;gBAAQ,KAAK,QAAQ,UAAU;OAAW;KAEzD,KAAK,2BACJ,IAAC;MAAQ,MAAK;gBAAQ,KAAK,QAAQ,UAAU;OAAW;QAEpD;GAEX,EAAC;;GACG,CACR;AACD,UAAS,QAAQ,IAAI,gBAAgB,sCAAsC;AAC3E,QAAO;AACR,EAAC;AAEF,IAAI,KAAK,WAAW,OAAO,MAAM;CAC/B,MAAM,EAAE,KAAK,GAAG,EAAE;CAClB,MAAM,MAAM,IAAI,WAAW,cAAc,EAAE,IAAI,KAAK,EAAE,IAAI,YAAY;CACtE,MAAM,MAAM,IAAI,IAAI,EAAE,IAAI;CAE1B,MAAM,WAAW,MAAM,EAAE,IAAI,UAAU;CACvC,IAAI,iBAAiB,SAAS,IAAI,SAAS,EAAE,UAAU;AAEvD,KAAI;AACF,OAAK,eACH,QAAO,EAAE,qBACP,IAAC;GAAY;GAAK,MAAM,IAAI;GAAM,OAAM;6BACtC,KAAC;IAAK,OAAM;;qBACV,IAAC,kBAAG,UAAU;qBACd,IAAC,iBAAE,iCAAgC;qBACnC,IAAC,iCACC,IAAC;MAAE,MAAK;gBAAI;OAAW,GACrB;;KACC;IACA,EACT,IACD;AAGH,MAAI,eAAe,WAAW,IAAI,CAChC,kBAAiB,eAAe,MAAM,EAAE;EAG1C,MAAM,gBAAgB,MAAM,IACzB,iBAAiB,OAAO,eAAe,EAAE;AAE5C,OAAK,eAAe,MAClB,QAAO,EAAE,qBACP,IAAC;GAAY;GAAK,MAAM,IAAI;GAAM,OAAM;6BACtC,KAAC;IAAK,OAAM;;qBACV,IAAC,kBAAG,UAAU;qBACd,KAAC;MAAE;MACoC;sBACrC,KAAC,qBAAK,KAAE,kBAAsB;;SAC5B;qBACJ,IAAC,iCACC,IAAC;MAAE,MAAK;gBAAI;OAAW,GACrB;;KACC;IACA,EACT,IACD;EAGH,MAAM,gBAAgB,cAAc,MAAM,KACxC,CAAC,SAAS,KAAK,QAAQ,0CACxB;AAED,MAAI,eAAe,UAAU;GAC3B,MAAM,cAAc,IAAI,YAAY,IAAI,WAAW;GACnD,MAAM,oBAAoB,cAAc,cAAc,SAAS;GAC/D,MAAM,YAAY,kBAAkB,OAAO,EACzC,KAAK,YAAY,KAClB,EAAC;AACF,UAAO,EAAE,SAAS,UAAU;EAC7B;AAED,SAAO,EAAE,qBACP,IAAC;GAAY;GAAK,MAAM,IAAI;GAAM,OAAM;6BACtC,KAAC;IAAK,OAAM;;qBACV,IAAC,kBAAG,UAAU;qBACd,KAAC;MAAE;MAC0C;sBAC3C,KAAC,qBAAK,KAAE,kBAAsB;;SAC5B;qBACJ,IAAC,iCACC,IAAC;MAAE,MAAK;gBAAI;OAAW,GACrB;;KACC;IACA,EACT,IACD;CACF,SAAQ,QAAQ;AACf,SAAO,EAAE,qBACP,IAAC;GAAY;GAAK,MAAM,IAAI;GAAM,OAAM;6BACtC,KAAC;IAAK,OAAM;;qBACV,IAAC,kBAAG,0BAA0B;qBAC9B,IAAC,iBAAE,qEAEC;qBACJ,IAAC,iCACC,IAAC;MAAE,MAAK;gBAAI;OAAW,GACrB;;KACC;IACA,EACT,IACD;CACF;AACF,EAAC;AAQF,eAAe,SACbC,KACAC,KACAC,UAA2B,CAAE,GAC0B;CACvD,MAAM,EAAE,QAAQ,SAAS,IAAI,GAAG;CAChC,IAAI,QAAQ,MAAM,MAAM,UACtB,IAAI,WAAW,YAAY;EACzB,OAAO;EACP,OAAO;EACP,OAAO,SAAS;CACjB,EAAC,CACH;CACD,IAAIC,WAA0C,MAAM,MAAM,SAAS;AACnE,SAAQ,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE;AACxC,SAAQ,MAAM,OAAO,SAAS;AAC9B,KAAI,QAAQ,WAAW,MAAM;EAC3B,MAAM,cAAc,CAAE;AACtB,OAAK,MAAM,QAAQ,MACjB,KAAI,MAAM,WAAW,KAAK,MAAM,QAAQ,QAAQ,CAC9C,aAAY,KAAK,KAAK;AAG1B,UAAQ;CACT;AACD,QAAO,YAAY,QAAQ,MAAM,SAAS,QAAQ;EAChD,MAAM,SAAS,SAAS,MAAM,UAAU;EACxC,MAAM,QAAQ,SAAS,cACpB,MAAM,SAAS,UAAU,IAAI,GAAG;AAEnC,MAAI,SAAS,KAAM;EACnB,MAAM,YAAY,IAAI,WAAW,YAAY;GAC3C,OAAO;GACP;GACA;EACD,EAAC;EACF,IAAI,IAAI;AACR;AACA,aAAW,MAAM,QAAQ,WAAW;AAClC,OACE,SAAS,KAAK,IAAI,MAAM,WAAW,KAAK,MAAM,QAAQ,QAAQ,IAC9D,MAAM,SAAS,SAAS,EACxB,OAAM,KAAK,KAAK;AAClB,cAAW;AACX;EACD;AACD,MAAI,IAAI,MAAO;CAChB;CACD,MAAMC,WAA+B,MAAM,MAAM,SAAS,UAAU,IAAI;AAExE,SAAQ,MAAM,MAAM,GAAG,OAAO;CAC9B,MAAM,WAAW,CAAC,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,UAAU,IAAI,CAAC,CAAC,EACpE,OAAO,gBAAgB;AAC1B,QAAO;EAAE,OAAO;EAAU;CAAU;AACrC;AAED,SAAS,SAASC,MAAkC;AAClD,QAAO,KAAK,MAAM,KAAK,CAAC,QAAQ,IAAI,SAAS,kBAAkB,KAAK,IAClE,KAAK,MAAM,KAAK,CAAC,QAAQ,IAAI,SAAS,kBAAkB,KAAK;AAChE;AAED,eAAe,WACbC,SACAD,MACAE,SACkB;AAClB,KAAI,WAAW,KAAM,QAAO;AAC5B,WAAU,iBAAiB,QAAQ;CACnC,MAAM,SAAS,MAAM,KAAK,UAAU,QAAQ;AAC5C,KAAI,UAAU,KAAM,QAAO;AAC3B,YAAW,MAAM,OAAO,OAAO,QAAQ,QAAQ,CAC7C,KACE,eAAe,WAAW,IAAI,QAAQ,QACtC,iBAAiB,IAAI,KAAK,UAAU,CAAC,KAAK,QAE1C,QAAO;AAGX,QAAO;AACR;AAED,SAAS,iBAAiBC,SAAyB;AACjD,QAAO,QACJ,aAAa,CACb,WAAW,CACX,QAAQ,MAAM,GAAG,CACjB,MAAM,CACN,QAAQ,QAAQ,GAAG;AACvB"}
|
|
1
|
+
{"version":3,"file":"pages.js","names":["properties: Record<string, string>","nextLink: URL | undefined","bot: BotImpl<unknown>","ctx: Context<unknown>","options: GetPostsOptions","lastPost: Announce | Create | undefined","nextPost: Object | undefined","post: Create | Announce","context: Context<unknown>","hashtag?: string","hashtag: string"],"sources":["../src/pages.tsx"],"sourcesContent":["// BotKit by Fedify: A framework for creating ActivityPub bots\n// Copyright (C) 2025–2026 Hong Minhee <https://hongminhee.org/>\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program. If not, see <https://www.gnu.org/licenses/>.\n/** @jsx react-jsx */\n/** @jsxImportSource hono/jsx */\nimport type { Context } from \"@fedify/fedify/federation\";\nimport {\n type Announce,\n type Create,\n getActorHandle,\n Hashtag,\n Image,\n Link,\n type Object,\n PUBLIC_COLLECTION,\n} from \"@fedify/vocab\";\nimport { Hono } from \"hono\";\nimport { decode } from \"html-entities\";\nimport { parseTemplate } from \"url-template\";\nimport type { BotImpl } from \"./bot-impl.ts\";\nimport { FollowButton } from \"./components/FollowButton.tsx\";\nimport { Follower } from \"./components/Follower.tsx\";\nimport { Layout } from \"./components/Layout.tsx\";\nimport { Message } from \"./components/Message.tsx\";\nimport { getMessageClass, isMessageObject, textXss } from \"./message-impl.ts\";\nimport type { MessageClass } from \"./message.ts\";\nimport type { Uuid } from \"./repository.ts\";\n\nexport interface Bindings {\n readonly bot: BotImpl<unknown>;\n readonly contextData: unknown;\n}\n\nexport interface Env {\n readonly Bindings: Bindings;\n}\n\nexport const app = new Hono<Env>();\n\napp.get(\"/\", async (c) => {\n const { bot } = c.env;\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const url = new URL(c.req.url);\n const handle = `@${bot.username}@${url.host}`;\n const icon = bot.icon instanceof Image\n ? bot.icon.url instanceof Link ? bot.icon.url.href : bot.icon.url\n : bot.icon;\n const iconWidth = bot.icon instanceof Image ? bot.icon.width : null;\n const iconHeight = bot.icon instanceof Image ? bot.icon.height : null;\n const image = bot.image instanceof Image\n ? bot.image.url instanceof Link ? bot.image.url.href : bot.image.url\n : bot.image;\n const imageWidth = bot.image instanceof Image ? bot.image.width : null;\n const imageHeight = bot.image instanceof Image ? bot.image.height : null;\n const followersCount = await bot.repository.countFollowers();\n const summaryChunks = bot.summary?.getHtml(session);\n const postsCount = await bot.repository.countMessages();\n const summary = summaryChunks == null\n ? null\n : (await Array.fromAsync(summaryChunks)).join(\"\");\n const properties: Record<string, string> = {};\n for (const name in bot.properties) {\n const value = bot.properties[name];\n const valueHtml = (await Array.fromAsync(value.getHtml(session))).join(\"\");\n properties[name] = valueHtml;\n }\n const offset = c.req.query(\"offset\");\n const { posts: messages, nextPost } = await getPosts(\n bot,\n ctx,\n offset ? { offset: Temporal.Instant.from(offset) } : {},\n );\n const activityLink = ctx.getActorUri(bot.identifier);\n const feedLink = new URL(\"/feed.xml\", url);\n let nextLink: URL | undefined;\n if (nextPost?.published != null) {\n nextLink = new URL(\"/\", url);\n nextLink.searchParams.set(\"offset\", nextPost.published.toString());\n }\n return c.html(\n <Layout\n bot={bot}\n host={url.host}\n activityLink={activityLink}\n feedLink={feedLink}\n >\n <header class=\"container\">\n {image && (\n <img\n src={image.href}\n width={imageWidth ?? undefined}\n height={imageHeight ?? undefined}\n alt={image instanceof Image\n ? image.name?.toString() ?? undefined\n : undefined}\n style=\"width: 100%; margin-bottom: 1em;\"\n />\n )}\n <hgroup>\n {icon && (\n <img\n src={icon.href}\n width={iconWidth ?? undefined}\n height={iconHeight ?? undefined}\n style=\"float: left; margin-right: 1em; height: 72;\"\n />\n )}\n <h1>\n <a href=\"/\">{bot.name ?? bot.username}</a>\n </h1>\n <p>\n <span style=\"user-select: all;\">{handle}</span> ·{\" \"}\n <a\n href=\"/feed.xml\"\n rel=\"alternate\"\n type=\"application/atom+xml\"\n title=\"Atom feed\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={18}\n height={18}\n viewBox=\"0 0 16 16\"\n aria-label=\"Atom feed\"\n >\n <path\n fill=\"currentColor\"\n d=\"M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2zm1.5 2.5c5.523 0 10 4.477 10 10a1 1 0 1 1-2 0a8 8 0 0 0-8-8a1 1 0 0 1 0-2m0 4a6 6 0 0 1 6 6a1 1 0 1 1-2 0a4 4 0 0 0-4-4a1 1 0 0 1 0-2m.5 7a1.5 1.5 0 1 1 0-3a1.5 1.5 0 0 1 0 3\"\n >\n </path>\n </svg>\n </a>{\" \"}\n ·{\" \"}\n <span>\n <a href=\"/followers\">\n {followersCount === 1\n ? `1 follower`\n : `${followersCount.toLocaleString(\"en\")} followers`}\n </a>\n </span>{\" \"}\n ·{\" \"}\n <span>\n {postsCount === 1\n ? `1 post`\n : `${postsCount.toLocaleString(\"en\")} posts`}\n </span>{\" \"}\n · <FollowButton bot={bot} />\n </p>\n </hgroup>\n {summary &&\n (\n <div\n dangerouslySetInnerHTML={{ __html: summary }}\n />\n )}\n {globalThis.Object.keys(properties).length > 0 && (\n <table>\n <tbody>\n {globalThis.Object.entries(properties).map(([name, value]) => (\n <tr>\n <th scope=\"row\" style=\"width: 1%; white-space: nowrap;\">\n <strong>{name}</strong>\n </th>\n <td\n dangerouslySetInnerHTML={{ __html: value }}\n />\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </header>\n <main class=\"container\">\n {messages.map((message) => (\n <Message message={message} session={session} />\n ))}\n </main>\n <footer class=\"container\">\n <nav style=\"display: block; text-align: end;\">\n {nextLink && (\n <a rel=\"next\" href={nextLink.href}>\n Older posts →\n </a>\n )}\n </nav>\n </footer>\n </Layout>,\n {\n headers: {\n Link:\n `<${activityLink.href}>; rel=\"alternate\"; type=\"application/activity+json\", ` +\n `<${feedLink.href}>; rel=\"alternate\"; type=\"application/atom+xml\"` +\n (nextLink\n ? `, <${nextLink.href}>; rel=\"next\"; type=\"text/html\"`\n : \"\"),\n },\n },\n );\n});\n\napp.get(\"/followers\", async (c) => {\n const { bot } = c.env;\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const followersCount = await bot.repository.countFollowers();\n const followers = await Array.fromAsync(bot.repository.getFollowers());\n\n const url = new URL(c.req.url);\n const activityLink = ctx.getActorUri(bot.identifier);\n const feedLink = new URL(\"/feed.xml\", url);\n\n return c.html(\n <Layout\n bot={bot}\n host={url.host}\n activityLink={activityLink}\n feedLink={feedLink}\n >\n <header class=\"container\">\n <h1>\n <a href=\"/\">←</a>{\" \"}\n {followersCount === 1\n ? `1 follower`\n : `${followersCount.toLocaleString(\"en\")} followers`}\n </h1>\n </header>\n <main class=\"container\">\n {followers.map((follower, index) => (\n <Follower\n key={follower.id?.href ?? index}\n actor={follower}\n session={session}\n />\n ))}\n </main>\n </Layout>,\n );\n});\n\napp.get(\"/tags/:hashtag\", async (c) => {\n const hashtag = c.req.param(\"hashtag\");\n const { bot } = c.env;\n const url = new URL(c.req.url);\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const offset = c.req.query(\"offset\");\n const { posts, nextPost } = await getPosts(bot, ctx, {\n hashtag,\n offset: offset == null ? undefined : Temporal.Instant.from(offset),\n });\n let nextLink: URL | undefined;\n if (nextPost?.published != null) {\n nextLink = new URL(`/tags/${encodeURIComponent(hashtag)}`, url);\n nextLink.searchParams.set(\"offset\", nextPost.published.toString());\n }\n return c.html(\n <Layout bot={bot} host={url.host} title={`#${hashtag}`}>\n <header class=\"container\">\n <h1>#{hashtag}</h1>\n </header>\n <main class=\"container\">\n {posts.map((message) => (\n <Message message={message} session={session} />\n ))}\n </main>\n <footer class=\"container\">\n <nav style=\"display: block; text-align: end;\">\n {nextLink && (\n <a rel=\"next\" href={nextLink.href}>Older posts →</a>\n )}\n </nav>\n </footer>\n </Layout>,\n {\n headers: nextLink == null ? {} : {\n Link: `<${nextLink.href}>; rel=\"next\"; type=\"text/html\"`,\n },\n },\n );\n});\n\napp.get(\"/message/:id\", async (c) => {\n const id = c.req.param(\"id\");\n const { bot } = c.env;\n const url = new URL(c.req.url);\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const post = await bot.repository.getMessage(id as Uuid);\n if (post == null || !isPublic(post)) return c.notFound();\n const message = await post.getObject(ctx);\n if (message == null || !isMessageObject(message)) return c.notFound();\n const activityLink = ctx.getObjectUri<MessageClass>(\n getMessageClass(message),\n { id },\n );\n const feedLink = new URL(\"/feed.xml\", url);\n let title = message.name;\n if (title == null) {\n title = message.summary ?? message.content;\n if (title != null) {\n title = decode(textXss.process(title.toString()));\n }\n }\n return c.html(\n <Layout\n bot={bot}\n host={url.host}\n activityLink={activityLink}\n feedLink={feedLink}\n title={title?.toString() ?? undefined}\n >\n <main class=\"container\">\n <Message message={message} session={session} />\n </main>\n </Layout>,\n {\n headers: {\n Link:\n `<${activityLink.href}>; rel=\"alternate\"; type=\"application/activity+json\", ` +\n `<${feedLink.href}>; rel=\"alternate\"; type=\"application/atom+xml\"`,\n },\n },\n );\n});\n\napp.get(\"/feed.xml\", async (c) => {\n const { bot } = c.env;\n const url = new URL(c.req.url);\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const session = bot.getSession(ctx);\n const { posts } = await getPosts(bot, ctx, { window: 30 });\n const botName = bot.name ?? bot.username;\n const canonicalUrl = new URL(\"/feed.xml\", url);\n const profileUrl = new URL(\"/\", url);\n const actorUrl = ctx.getActorUri(bot.identifier);\n c.header(\n \"Link\",\n `<${actorUrl.href}>; rel=\"alternate\"; type=\"application/activity+json\", ` +\n `<${profileUrl.href}>; rel=\"alternate\"; type=\"text/html\"`,\n );\n const response = await c.render(\n <feed xmlns=\"http://www.w3.org/2005/Atom\">\n <id>{canonicalUrl.href}</id>\n <link rel=\"self\" type=\"application/atom+xml\" href={canonicalUrl.href} />\n <link rel=\"alternate\" type=\"text/html\" href={profileUrl.href} />\n <link\n rel=\"alternate\"\n type=\"application/activity+json\"\n href={actorUrl.href}\n />\n <title>{botName} (@{bot.username}@{url.host})</title>\n <author>\n <name>{botName}</name>\n <uri>{profileUrl.href}</uri>\n </author>\n {posts.length > 0 && (\n <updated>\n {(posts[0].updated ?? posts[0].published)?.toString()}\n </updated>\n )}\n {posts.map(async (post) => {\n const activityUrl = post.id;\n if (activityUrl == null) return undefined;\n const permalink =\n (post.url instanceof Link ? post.url.href : post.url) ?? activityUrl;\n const author = post.attributionId?.href === session.actorId?.href\n ? await session.getActor()\n : await post.getAttribution({\n documentLoader: ctx.documentLoader,\n contextLoader: ctx.contextLoader,\n suppressError: true,\n });\n const authorName = author?.name ?? author?.preferredUsername ??\n (author == null ? undefined : await getActorHandle(author));\n const authorUrl =\n (author?.url instanceof Link ? author.url.href : author?.url) ??\n author?.id;\n const updated = post.updated ?? post.published;\n let title = post.name;\n if (title == null) {\n title = post.summary ?? post.content;\n if (title != null) {\n title = decode(textXss.process(title.toString()));\n }\n }\n return (\n <entry>\n <id>{permalink.href}</id>\n <link rel=\"alternate\" type=\"text/html\" href={permalink.href} />\n <link\n rel=\"alternate\"\n type=\"application/activity+json\"\n href={activityUrl.href}\n />\n {authorName &&\n (\n <author>\n <name>{authorName}</name>\n {authorUrl &&\n <uri>{authorUrl.href}</uri>}\n </author>\n )}\n {post.published && (\n <published>{post.published.toString()}</published>\n )}\n {updated && <updated>{updated.toString()}</updated>}\n {title && <title>{title}</title>}\n {post.summary && (\n <summary type=\"html\">{post.summary.toString()}</summary>\n )}\n {post.content && (\n <content type=\"html\">{post.content.toString()}</content>\n )}\n </entry>\n );\n })}\n </feed>,\n );\n response.headers.set(\"Content-Type\", \"application/atom+xml; charset=utf-8\");\n return response;\n});\n\napp.post(\"/follow\", async (c) => {\n const { bot } = c.env;\n const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);\n const url = new URL(c.req.url);\n\n const formData = await c.req.formData();\n let followerHandle = formData.get(\"handle\")?.toString();\n\n try {\n if (!followerHandle) {\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Error</h1>\n <p>Follower handle is required.</p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 400,\n );\n }\n\n if (followerHandle.startsWith(\"@\")) {\n followerHandle = followerHandle.slice(1);\n }\n\n const webfingerData = await ctx\n .lookupWebFinger(`acct:${followerHandle}`);\n\n if (!webfingerData?.links) {\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Error</h1>\n <p>\n No links found in webfinger data for{\" \"}\n <code>@{followerHandle}</code>.\n </p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 400,\n );\n }\n\n const subscribeLink = webfingerData.links.find(\n (link) => link.rel === \"http://ostatus.org/schema/1.0/subscribe\",\n );\n\n if (subscribeLink?.template) {\n const botActorUri = ctx.getActorUri(bot.identifier);\n const followUrlTemplate = parseTemplate(subscribeLink.template);\n const followUrl = followUrlTemplate.expand({\n uri: botActorUri.href,\n });\n return c.redirect(followUrl);\n }\n\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Error</h1>\n <p>\n No follow link found in WebFinger data for{\" \"}\n <code>@{followerHandle}</code>.\n </p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 400,\n );\n } catch (_error) {\n return c.html(\n <Layout bot={bot} host={url.host} title=\"Error\">\n <main class=\"container\">\n <h1>Internal Server Error</h1>\n <p>\n An internal server error occurred while processing your request.\n </p>\n <p>\n <a href=\"/\">Go back</a>\n </p>\n </main>\n </Layout>,\n 500,\n );\n }\n});\n\ninterface GetPostsOptions {\n readonly hashtag?: string;\n readonly offset?: Temporal.Instant;\n readonly window?: number;\n}\n\nasync function getPosts(\n bot: BotImpl<unknown>,\n ctx: Context<unknown>,\n options: GetPostsOptions = {},\n): Promise<{ posts: MessageClass[]; nextPost?: Object }> {\n const { offset, window = 15 } = options;\n let posts = await Array.fromAsync(\n bot.repository.getMessages({\n order: \"newest\",\n until: offset,\n limit: window * 2,\n }),\n );\n let lastPost: Announce | Create | undefined = posts[posts.length - 1];\n posts = posts.slice(0, posts.length - 1);\n posts = posts.filter(isPublic);\n if (options.hashtag != null) {\n const taggedPosts = [];\n for (const post of posts) {\n if (await hasHashtag(ctx, post, options.hashtag)) {\n taggedPosts.push(post);\n }\n }\n posts = taggedPosts;\n }\n while (lastPost != null && posts.length < window) {\n const limit = (window - posts.length) * 2;\n const until = lastPost.published ??\n (await lastPost.getObject(ctx))?.published ??\n undefined;\n if (until == null) break;\n const nextPosts = bot.repository.getMessages({\n order: \"newest\",\n until,\n limit,\n });\n let i = 0;\n lastPost = undefined;\n for await (const post of nextPosts) {\n if (\n isPublic(post) && await hasHashtag(ctx, post, options.hashtag) &&\n posts.length < window + 1\n ) posts.push(post);\n lastPost = post;\n i++;\n }\n if (i < limit) break;\n }\n const nextPost: Object | undefined = await posts[window]?.getObject(ctx) ??\n undefined;\n posts = posts.slice(0, window);\n const messages = (await Promise.all(posts.map((p) => p.getObject(ctx))))\n .filter(isMessageObject);\n return { posts: messages, nextPost };\n}\n\nfunction isPublic(post: Create | Announce): boolean {\n return post.toIds.some((url) => url.href === PUBLIC_COLLECTION.href) ||\n post.ccIds.some((url) => url.href === PUBLIC_COLLECTION.href);\n}\n\nasync function hasHashtag(\n context: Context<unknown>,\n post: Create | Announce,\n hashtag?: string,\n): Promise<boolean> {\n if (hashtag == null) return true;\n hashtag = normalizeHashtag(hashtag);\n const object = await post.getObject(context);\n if (object == null) return false;\n for await (const tag of object.getTags(context)) {\n if (\n tag instanceof Hashtag && tag.name != null &&\n normalizeHashtag(tag.name.toString()) === hashtag\n ) {\n return true;\n }\n }\n return false;\n}\n\nfunction normalizeHashtag(hashtag: string): string {\n return hashtag\n .toLowerCase()\n .trimStart()\n .replace(/^#/, \"\")\n .trim()\n .replace(/\\s+/g, \"\");\n}\n"],"mappings":"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"}
|