···11import { AtpAgent } from "npm:@atproto/api";
22-import { serveDir } from "jsr:@std/http/file-server";
22+import { serveDir, serveFile } from "jsr:@std/http/file-server";
3344import Actor from "./actor.ts";
55···88Deno.serve(async (req) => {
99 const url = new URL(req.url);
1010 const path = url.pathname;
1111+ const redir = `${url.protocol}${url.host}`;
1212+ const query = new URLSearchParams(url.search);
11131414+ // wrangle bots
1515+ if (path === "/robots.txt") {
1616+ return serveFile(req, "./static/robots.txt");
1717+ }
1818+1919+ // serve static files
1220 if (path.startsWith("/static")) {
1321 return serveDir(req, { quiet: true });
1422 }
···1624 // handle trailing slashes
1725 if (path.at(-1) !== "/") {
1826 return Response.redirect(
1919- `${url.protocol}${url.host}${url.pathname}/`,
2727+ `${redir}${url.pathname}/`,
2028 );
2129 }
2230···2533 const profilePattern = new URLPattern({ pathname: "/profile/:actor/" });
2634 if (profilePattern.test(url)) {
2735 const actorName = profilePattern.exec(url)?.pathname.groups.actor;
2828- const actor = new Actor(actorName);
2929-3030- return new Response(await actor.HTML(), html_headers);
3636+ const actor = new Actor(actorName!);
3737+ const cursor = query.get("cursor");
3838+ if (cursor) return new Response(await actor.HTML(cursor), html_headers);
3939+ else return new Response(await actor.HTML(), html_headers);
3140 }
32413342 // RAW PROFILE
···3645 });
3746 if (rawProfilePattern.test(url)) {
3847 const actorName = rawProfilePattern.exec(url)?.pathname.groups.actor;
3939- const actor = new Actor(actorName);
4848+ const actor = new Actor(actorName!);
40494150 return new Response(await actor.Raw(), json_headers);
4251 }
5252+5353+ // FOLLOWERS, FOLLOWING
5454+ const pageProfilePattern = new URLPattern({
5555+ pathname: "/profile/:actor/:page/",
5656+ });
5757+ if (pageProfilePattern.test(url)) {
5858+ const actorName = pageProfilePattern.exec(url)?.pathname.groups.actor;
5959+ const pageName = pageProfilePattern.exec(url)?.pathname.groups.page;
6060+ const actor = new Actor(actorName!);
6161+6262+ if (pageName === "followers") {
6363+ const cursor = query.get("cursor");
6464+ if (cursor) {
6565+ return new Response(await actor.Followers(cursor), html_headers);
6666+ } else return new Response(await actor.Followers(), html_headers);
6767+ }
6868+ if (pageName === "follows") {
6969+ const cursor = query.get("cursor");
7070+ if (cursor) {
7171+ return new Response(await actor.Follows(cursor), html_headers);
7272+ } else return new Response(await actor.Follows(), html_headers);
7373+ }
7474+ }
4375 } catch (error) {
4476 return new Response(
4577 `<head><meta name="color-scheme" content="light dark"></head>\n${error}`,
4646- headers,
7878+ html_headers,
4779 );
4880 }
4981
+117
static/robots.txt
···11+# Our policy (taken from sr.ht, see LICENSE below)
22+#
33+# Allowed:
44+# - Search engine indexers
55+# - Archival services (e.g. IA)
66+#
77+# Disallowed:
88+# - Marketing or SEO crawlers
99+# - Bots which are too agressive by default. This is subjective, if you annoy
1010+# our sysadmins you'll be blocked.
1111+#
1212+# Reach out to mail@jordanreger.com if you have questions.
1313+1414+# Too aggressive, marketing/SEO
1515+User-agent: SemrushBot
1616+Disallow: /
1717+1818+# Too aggressive, marketing/SEO
1919+User-agent: SemrushBot-SA
2020+Disallow: /
2121+2222+# Marketing/SEO
2323+User-agent: AhrefsBot
2424+Disallow: /
2525+2626+# Marketing/SEO
2727+User-agent: dotbot
2828+Disallow: /
2929+3030+# Marketing/SEO
3131+User-agent: rogerbot
3232+Disallow: /
3333+3434+User-agent: BLEXBot
3535+Disallow: /
3636+3737+# Huwei something or another, badly behaved
3838+User-agent: AspiegelBot
3939+Disallow: /
4040+4141+# Marketing/SEO
4242+User-agent: ZoominfoBot
4343+Disallow: /
4444+4545+# YandexBot is a dickhead, too aggressive
4646+User-agent: Yandex
4747+Disallow: /
4848+4949+# Marketing/SEO
5050+User-agent: MJ12bot
5151+Disallow: /
5252+5353+# Marketing/SEO
5454+User-agent: DataForSeoBot
5555+Disallow: /
5656+5757+# Used for Alexa, I guess, who cares
5858+User-agent: Amazonbot
5959+Disallow: /
6060+6161+# No
6262+User-agent: turnitinbot
6363+Disallow: /
6464+6565+User-agent: Turnitin
6666+Disallow: /
6767+6868+# Does not respect * directives
6969+User-agent: Seekport Crawler
7070+Disallow: /
7171+7272+# No thanks
7373+User-agent: GPTBot
7474+Disallow: /
7575+7676+# Fairly certain that this is an LLM data vacuum
7777+User-agent: ClaudeBot
7878+Disallow: /
7979+8080+# Same
8181+User-agent: Google-Extended
8282+Disallow: /
8383+8484+# Marketing
8585+User-agent: serpstatbot
8686+Disallow: /
8787+8888+# Marketing/SEO
8989+User-agent: barkrowler
9090+Disallow: /
9191+9292+# Very aggressive, used for TikTok or something
9393+User-agent: Bytespider
9494+Disallow: /
9595+9696+9797+# LICENSE (https://git.sr.ht/~sircmpwn/sr.ht-nginx/tree/master/item/LICENSE)
9898+# ===============================================================================
9999+# Copyright (c) 2020 Drew DeVault
100100+101101+# Permission is hereby granted, free of charge, to any person obtaining a copy of
102102+# this software and associated documentation files (the "Software"), to deal in
103103+# the Software without restriction, including without limitation the rights to
104104+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
105105+# of the Software, and to permit persons to whom the Software is furnished to do
106106+# so, subject to the following conditions:
107107+108108+# The above copyright notice and this permission notice shall be included in all
109109+# copies or substantial portions of the Software.
110110+111111+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
112112+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
113113+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
114114+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
115115+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
116116+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
117117+# SOFTWARE.