import { STATUS_CODE, STATUS_TEXT } from "@std/http";
import { Client, simpleFetchHandler } from "@atcute/client";
import { is } from "@atcute/lexicons";
import { isActorIdentifier } from "@atcute/lexicons/syntax";
import { AppBskyActorProfile } from "@atcute/bluesky";
const ROOT = new URLPattern({ pathname: "/" });
const IDENTIFIER_ROUTE = new URLPattern({ pathname: "/avatar/:identifier" });
const slingshot = new Client({
handler: simpleFetchHandler({ service: "https://slingshot.microcosm.blue" }),
});
function generateSpiel(origin: string) {
return `
silhouette
Quickly get the URL to your Bluesky profile photo using an identifier (handle or DID). Go to:
${origin}/avatar/<your-identifier>
For example:
${origin}/avatar/graham.systems
`;
}
// Algorithm:
// 1. Resolve minidoc from identifier in URL
// 2. Resolve Bluesky actor profile from PDS
// 3. Return 303 with profile picture blob URL
export async function handler(req: Request): Promise {
if (ROOT.exec(req.url)) {
const url = new URL(req.url);
return new Response(generateSpiel(url.origin), {
status: STATUS_CODE.OK,
statusText: STATUS_TEXT[STATUS_CODE.OK],
headers: {
"Content-Type": "text/html",
},
});
}
const match = IDENTIFIER_ROUTE.exec(req.url);
if (!match) {
return new Response(null, {
status: STATUS_CODE.NotFound,
statusText: STATUS_TEXT[STATUS_CODE.NotFound],
});
} else if (req.method !== "GET") {
return new Response(null, {
status: STATUS_CODE.MethodNotAllowed,
statusText: STATUS_TEXT[STATUS_CODE.MethodNotAllowed],
});
}
const identifier = match.pathname.groups.identifier;
if (!isActorIdentifier(identifier)) {
return Response.json({
identifier,
message: `invalid identifier ${identifier}`,
}, {
status: STATUS_CODE.BadRequest,
statusText: STATUS_TEXT[STATUS_CODE.BadRequest],
});
}
const minidoc = await slingshot.get(
"com.bad-example.identity.resolveMiniDoc",
{
params: {
identifier,
},
},
);
if (!minidoc.ok) {
return Response.json({
identifier,
message: `failed to resolve identifier ${identifier}`,
}, {
status: STATUS_CODE.InternalServerError,
statusText: STATUS_TEXT[STATUS_CODE.InternalServerError],
});
} else if (minidoc.status > 400) {
return Response.json({
identifier,
message: `error from Slingshot`,
error: minidoc.data,
}, {
status: STATUS_CODE.InternalServerError,
statusText: STATUS_TEXT[STATUS_CODE.InternalServerError],
});
}
const pds = new Client({
handler: simpleFetchHandler({ service: minidoc.data.pds }),
});
const record = await pds.get("com.atproto.repo.getRecord", {
params: {
collection: "app.bsky.actor.profile",
rkey: "self",
repo: minidoc.data.did,
},
});
if (!record.ok || record.status > 400) {
return Response.json({
identifier,
pds: minidoc.data.pds,
message: `failed to resolve app.bsky.actor.profile for ${identifier}`,
}, {
status: record.status || STATUS_CODE.InternalServerError,
statusText: STATUS_TEXT[
STATUS_CODE.InternalServerError
],
});
}
const profile = record.data.value;
if (!is(AppBskyActorProfile.mainSchema, profile)) {
return Response.json({
identifier,
pds: minidoc.data.pds,
message: `profile record does not match app.bsky.actor.profile`,
profile,
}, {
status: STATUS_CODE.PreconditionFailed,
statusText: STATUS_TEXT[STATUS_CODE.PreconditionFailed],
});
} else if (!profile.avatar) {
return Response.json({
identifier,
pds: minidoc.data.pds,
message: "profile has no avatar",
}, {
status: STATUS_CODE.NotFound,
statusText: STATUS_TEXT[STATUS_CODE.NotFound],
});
}
const blobUrl = new URL("/xrpc/com.atproto.sync.getBlob", minidoc.data.pds);
const cid = "ref" in profile.avatar
? profile.avatar.ref.$link
: profile.avatar.cid;
blobUrl.searchParams.set("did", minidoc.data.did);
blobUrl.searchParams.set("cid", cid);
return Response.redirect(blobUrl, STATUS_CODE.SeeOther);
}
if (import.meta.main) {
Deno.serve(handler);
}