@fedify/botkit 0.3.0-dev.142 → 0.3.0-dev.148
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/components/Follower.d.ts +20 -0
- package/dist/components/Follower.d.ts.map +1 -0
- package/dist/components/Follower.js +40 -0
- package/dist/components/Follower.js.map +1 -0
- package/dist/deno.js +1 -1
- package/dist/deno.js.map +1 -1
- package/dist/pages.d.ts +2 -2
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +38 -1
- package/dist/pages.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
|
|
2
|
+
Date.prototype.toTemporalInstant = toTemporalInstant;
|
|
3
|
+
import { Session } from "../session.js";
|
|
4
|
+
import { Actor } from "@fedify/fedify/vocab";
|
|
5
|
+
import * as hono_utils_html0 from "hono/utils/html";
|
|
6
|
+
|
|
7
|
+
//#region src/components/Follower.d.ts
|
|
8
|
+
interface FollowerProps {
|
|
9
|
+
readonly actor: Actor;
|
|
10
|
+
readonly session: Session<unknown>;
|
|
11
|
+
}
|
|
12
|
+
declare function Follower({
|
|
13
|
+
actor,
|
|
14
|
+
session
|
|
15
|
+
}: FollowerProps): Promise<hono_utils_html0.HtmlEscapedString>;
|
|
16
|
+
//# sourceMappingURL=Follower.d.ts.map
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { Follower, FollowerProps };
|
|
20
|
+
//# sourceMappingURL=Follower.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Follower.d.ts","names":[],"sources":["../../src/components/Follower.tsx"],"sourcesContent":[],"mappings":";;;;;;;UAoBiB,aAAA;kBACC;oBACE;;iBAGE,QAAA;;;GAA6B,gBAAa,QAAA,gBAAA,CAAA,iBAAA;AALhE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
|
|
3
|
+
Date.prototype.toTemporalInstant = toTemporalInstant;
|
|
4
|
+
|
|
5
|
+
import { Link, getActorHandle } from "@fedify/fedify/vocab";
|
|
6
|
+
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/components/Follower.tsx
|
|
9
|
+
async function Follower({ actor, session }) {
|
|
10
|
+
const { context } = session;
|
|
11
|
+
const author = actor;
|
|
12
|
+
const authorIcon = await actor?.getIcon({
|
|
13
|
+
documentLoader: context.documentLoader,
|
|
14
|
+
contextLoader: context.contextLoader,
|
|
15
|
+
suppressError: true
|
|
16
|
+
});
|
|
17
|
+
const authorHandle = await getActorHandle(author);
|
|
18
|
+
return /* @__PURE__ */ jsx("article", { children: /* @__PURE__ */ jsx("header", { children: author?.id ? /* @__PURE__ */ jsxs("hgroup", { children: [
|
|
19
|
+
authorIcon?.url && /* @__PURE__ */ jsx("img", {
|
|
20
|
+
src: authorIcon.url instanceof Link ? authorIcon.url.href?.href : authorIcon.url.href,
|
|
21
|
+
width: authorIcon.width ?? void 0,
|
|
22
|
+
height: authorIcon.height ?? void 0,
|
|
23
|
+
alt: authorIcon.name?.toString() ?? void 0,
|
|
24
|
+
style: "float: left; margin-right: 1em; height: 64px;"
|
|
25
|
+
}),
|
|
26
|
+
/* @__PURE__ */ jsx("h3", { children: /* @__PURE__ */ jsx("a", {
|
|
27
|
+
href: author.url?.href?.toString() ?? author.id.href,
|
|
28
|
+
children: author.name
|
|
29
|
+
}) }),
|
|
30
|
+
" ",
|
|
31
|
+
/* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("span", {
|
|
32
|
+
style: "user-select: all;",
|
|
33
|
+
children: authorHandle
|
|
34
|
+
}) })
|
|
35
|
+
] }) : /* @__PURE__ */ jsx("em", { children: "(Deleted account)" }) }) });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//#endregion
|
|
39
|
+
export { Follower };
|
|
40
|
+
//# sourceMappingURL=Follower.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Follower.js","names":[],"sources":["../../src/components/Follower.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 Actor, getActorHandle, Link } from \"@fedify/fedify/vocab\";\nimport type { Session } from \"../session.ts\";\n\nexport interface FollowerProps {\n readonly actor: Actor;\n readonly session: Session<unknown>;\n}\n\nexport async function Follower({ actor, session }: FollowerProps) {\n const { context } = session;\n const author = actor;\n const authorIcon = await actor?.getIcon({\n documentLoader: context.documentLoader,\n contextLoader: context.contextLoader,\n suppressError: true,\n });\n const authorHandle = await getActorHandle(author);\n\n return (\n <article>\n <header>\n {author?.id\n ? (\n <hgroup>\n {authorIcon?.url && (\n <img\n src={authorIcon.url instanceof Link\n ? authorIcon.url.href?.href\n : authorIcon.url.href}\n width={authorIcon.width ?? undefined}\n height={authorIcon.height ?? undefined}\n alt={authorIcon.name?.toString() ?? undefined}\n style=\"float: left; margin-right: 1em; height: 64px;\"\n />\n )}\n <h3>\n <a href={author.url?.href?.toString() ?? author.id.href}>\n {author.name}\n </a>\n </h3>{\" \"}\n <p>\n <span style=\"user-select: all;\">{authorHandle}</span>\n </p>\n </hgroup>\n )\n : <em>(Deleted account)</em>}\n </header>\n </article>\n );\n}\n"],"mappings":";;;;;;;;AAyBA,eAAsB,SAAS,EAAE,OAAO,SAAwB,EAAE;CAChE,MAAM,EAAE,SAAS,GAAG;CACpB,MAAM,SAAS;CACf,MAAM,aAAa,MAAM,OAAO,QAAQ;EACtC,gBAAgB,QAAQ;EACxB,eAAe,QAAQ;EACvB,eAAe;CAChB,EAAC;CACF,MAAM,eAAe,MAAM,eAAe,OAAO;AAEjD,wBACE,IAAC,uCACC,IAAC,sBACE,QAAQ,qBAEL,KAAC;EACE,YAAY,uBACX,IAAC;GACC,KAAK,WAAW,eAAe,OAC3B,WAAW,IAAI,MAAM,OACrB,WAAW,IAAI;GACnB,OAAO,WAAW;GAClB,QAAQ,WAAW;GACnB,KAAK,WAAW,MAAM,UAAU;GAChC,OAAM;IACN;kBAEJ,IAAC,kCACC,IAAC;GAAE,MAAM,OAAO,KAAK,MAAM,UAAU,IAAI,OAAO,GAAG;aAChD,OAAO;IACN,GACD;EAAC;kBACN,IAAC,iCACC,IAAC;GAAK,OAAM;aAAqB;IAAoB,GACnD;KACG,mBAET,IAAC,kBAAG,sBAAsB,GACvB,GACD;AAEb"}
|
package/dist/deno.js
CHANGED
package/dist/deno.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deno.js","names":[],"sources":["../deno.json"],"sourcesContent":["{\n \"name\": \"@fedify/botkit\",\n \"version\": \"0.3.0-dev.
|
|
1
|
+
{"version":3,"file":"deno.js","names":[],"sources":["../deno.json"],"sourcesContent":["{\n \"name\": \"@fedify/botkit\",\n \"version\": \"0.3.0-dev.148+bba373cc\",\n \"license\": \"AGPL-3.0-only\",\n \"exports\": {\n \".\": \"./src/mod.ts\",\n \"./bot\": \"./src/bot.ts\",\n \"./emoji\": \"./src/emoji.ts\",\n \"./events\": \"./src/events.ts\",\n \"./follow\": \"./src/follow.ts\",\n \"./message\": \"./src/message.ts\",\n \"./poll\": \"./src/poll.ts\",\n \"./reaction\": \"./src/reaction.ts\",\n \"./repository\": \"./src/repository.ts\",\n \"./session\": \"./src/session.ts\",\n \"./text\": \"./src/text.ts\"\n },\n \"imports\": {\n \"@fedify/markdown-it-hashtag\": \"jsr:@fedify/markdown-it-hashtag@^0.3.0\",\n \"@fedify/markdown-it-mention\": \"jsr:@fedify/markdown-it-mention@^0.3.0\",\n \"@phensley/language-tag\": \"npm:@phensley/language-tag@^1.12.2\",\n \"html-entities\": \"npm:html-entities@^2.6.0\",\n \"markdown-it\": \"npm:markdown-it@^14.1.0\",\n \"mime-db\": \"npm:mime-db@^1.54.0\",\n \"tsdown\": \"npm:tsdown@^0.12.8\",\n \"uuid\": \"npm:uuid@^11.1.0\",\n \"xss\": \"npm:xss@^1.0.15\"\n },\n \"exclude\": [\n \"dist\",\n \"junit.xml\",\n \"src/css\"\n ],\n \"fmt\": {\n \"exclude\": [\n \"*.md\",\n \"*.yaml\",\n \"*.yml\",\n \"src/static/*.ts\"\n ]\n },\n \"tasks\": {\n \"test\": \"deno test --allow-env=NODE_V8_COVERAGE,JEST_WORKER_ID --allow-net=hollo.social --parallel\",\n \"test:node\": \"pnpm install && pnpm test\",\n \"test-all\": {\n \"dependencies\": [\n \"check\",\n \"test\",\n \"test:node\"\n ]\n },\n \"coverage\": \"deno task test --coverage --clean && deno coverage --html\"\n }\n}\n"],"mappings":";;;;;WACU;cACG;cACA;cACA;CACT,KAAK;CACL,SAAS;CACT,WAAW;CACX,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,UAAU;CACV,cAAc;CACd,gBAAgB;CAChB,aAAa;CACb,UAAU;AACX;cACU;CACT,+BAA+B;CAC/B,+BAA+B;CAC/B,0BAA0B;CAC1B,iBAAiB;CACjB,eAAe;CACf,WAAW;CACX,UAAU;CACV,QAAQ;CACR,OAAO;AACR;cACU;CACT;CACA;CACA;AACD;UACM,EACL,WAAW;CACT;CACA;CACA;CACA;AACD,EACF;YACQ;CACP,QAAQ;CACR,aAAa;CACb,YAAY,EACV,gBAAgB;EACd;EACA;EACA;CACD,EACF;CACD,YAAY;AACb;mBApDH;;;;;;;;;AAqDC"}
|
package/dist/pages.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Temporal, toTemporalInstant } from "@js-temporal/polyfill";
|
|
|
2
2
|
Date.prototype.toTemporalInstant = toTemporalInstant;
|
|
3
3
|
import { BotImpl } from "./bot-impl.js";
|
|
4
4
|
import { Hono } from "hono";
|
|
5
|
-
import * as
|
|
5
|
+
import * as hono_types2 from "hono/types";
|
|
6
6
|
|
|
7
7
|
//#region src/pages.d.ts
|
|
8
8
|
interface Bindings {
|
|
@@ -12,7 +12,7 @@ interface Bindings {
|
|
|
12
12
|
interface Env {
|
|
13
13
|
readonly Bindings: Bindings;
|
|
14
14
|
}
|
|
15
|
-
declare const app: Hono<Env,
|
|
15
|
+
declare const app: Hono<Env, hono_types2.BlankSchema, "/">;
|
|
16
16
|
//# sourceMappingURL=pages.d.ts.map
|
|
17
17
|
|
|
18
18
|
//#endregion
|
package/dist/pages.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.d.ts","names":[],"sources":["../src/pages.tsx"],"sourcesContent":[],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"pages.d.ts","names":[],"sources":["../src/pages.tsx"],"sourcesContent":[],"mappings":";;;;;;;UAsCiB,QAAA;gBACD;;;UAIC,GAAA;qBACI;;AANJ,cASJ,GATY,EAST,IARA,CAQA,GARO,EAQP,WAAA,CAAA,WAAA,EARO,GAAA,CAAA;AAIvB"}
|
package/dist/pages.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { getMessageClass, isMessageObject, textXss } from "./message-impl.js";
|
|
6
6
|
import { Layout } from "./components/Layout.js";
|
|
7
7
|
import { Message } from "./components/Message.js";
|
|
8
|
+
import { Follower } from "./components/Follower.js";
|
|
8
9
|
import { Hashtag, Image, Link, PUBLIC_COLLECTION, getActorHandle } from "@fedify/fedify/vocab";
|
|
9
10
|
import { decode } from "html-entities";
|
|
10
11
|
import { Hono } from "hono";
|
|
@@ -97,7 +98,10 @@ app.get("/", async (c) => {
|
|
|
97
98
|
" ",
|
|
98
99
|
"·",
|
|
99
100
|
" ",
|
|
100
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
101
|
+
/* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx("a", {
|
|
102
|
+
href: "/followers",
|
|
103
|
+
children: followersCount === 1 ? `1 follower` : `${followersCount.toLocaleString("en")} followers`
|
|
104
|
+
}) }),
|
|
101
105
|
" ",
|
|
102
106
|
"·",
|
|
103
107
|
" ",
|
|
@@ -134,6 +138,39 @@ app.get("/", async (c) => {
|
|
|
134
138
|
]
|
|
135
139
|
}), { headers: { Link: `<${activityLink.href}>; rel="alternate"; type="application/activity+json", <${feedLink.href}>; rel="alternate"; type="application/atom+xml"` + (nextLink ? `, <${nextLink.href}>; rel="next"; type="text/html"` : "") } });
|
|
136
140
|
});
|
|
141
|
+
app.get("/followers", async (c) => {
|
|
142
|
+
const { bot } = c.env;
|
|
143
|
+
const ctx = bot.federation.createContext(c.req.raw, c.env.contextData);
|
|
144
|
+
const session = bot.getSession(ctx);
|
|
145
|
+
const followersCount = await bot.repository.countFollowers();
|
|
146
|
+
const followers = await Array.fromAsync(bot.repository.getFollowers());
|
|
147
|
+
const url = new URL(c.req.url);
|
|
148
|
+
const activityLink = ctx.getActorUri(bot.identifier);
|
|
149
|
+
const feedLink = new URL("/feed.xml", url);
|
|
150
|
+
return c.html(/* @__PURE__ */ jsxs(Layout, {
|
|
151
|
+
bot,
|
|
152
|
+
host: url.host,
|
|
153
|
+
activityLink,
|
|
154
|
+
feedLink,
|
|
155
|
+
children: [/* @__PURE__ */ jsx("header", {
|
|
156
|
+
class: "container",
|
|
157
|
+
children: /* @__PURE__ */ jsxs("h1", { children: [
|
|
158
|
+
/* @__PURE__ */ jsx("a", {
|
|
159
|
+
href: "/",
|
|
160
|
+
children: "←"
|
|
161
|
+
}),
|
|
162
|
+
" ",
|
|
163
|
+
followersCount === 1 ? `1 follower` : `${followersCount.toLocaleString("en")} followers`
|
|
164
|
+
] })
|
|
165
|
+
}), /* @__PURE__ */ jsx("main", {
|
|
166
|
+
class: "container",
|
|
167
|
+
children: followers.map((follower, index) => /* @__PURE__ */ jsx(Follower, {
|
|
168
|
+
actor: follower,
|
|
169
|
+
session
|
|
170
|
+
}, follower.id?.href ?? index))
|
|
171
|
+
})]
|
|
172
|
+
}));
|
|
173
|
+
});
|
|
137
174
|
app.get("/tags/:hashtag", async (c) => {
|
|
138
175
|
const hashtag = c.req.param("hashtag");
|
|
139
176
|
const { bot } = c.env;
|
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/fedify/vocab\";\nimport { Hono } from \"hono\";\nimport { decode } from \"html-entities\";\nimport type { BotImpl } from \"./bot-impl.ts\";\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 {followersCount === 1\n ? `1 follower`\n : `${followersCount.toLocaleString(\"en\")} followers`}\n </span>{\" \"}\n ·{\" \"}\n <span>\n {postsCount === 1\n ? `1 post`\n : `${postsCount.toLocaleString(\"en\")} posts`}\n </span>\n {\" \"}\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(\"/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\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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"}
|
|
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/fedify/vocab\";\nimport { Hono } from \"hono\";\nimport { decode } from \"html-entities\";\nimport type { BotImpl } from \"./bot-impl.ts\";\nimport { Layout } from \"./components/Layout.tsx\";\nimport { Message } from \"./components/Message.tsx\";\nimport { Follower } from \"./components/Follower.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 {\" \"}\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\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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/botkit",
|
|
3
|
-
"version": "0.3.0-dev.
|
|
3
|
+
"version": "0.3.0-dev.148+bba373cc",
|
|
4
4
|
"description": "A framework for creating ActivityPub bots",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"author": {
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"README.md"
|
|
85
85
|
],
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@fedify/fedify": "^1.8.
|
|
87
|
+
"@fedify/fedify": "^1.8.8",
|
|
88
88
|
"@fedify/markdown-it-hashtag": "^0.3.0",
|
|
89
89
|
"@fedify/markdown-it-mention": "^0.3.0",
|
|
90
90
|
"@js-temporal/polyfill": "^0.5.1",
|