Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139import { afterEach, describe, expect, test, vi } from "vitest";import type { HandleResolver } from "@atcute/identity-resolver";import { FallbackHandleResolver, handleResolverFor, handleResolverUrls} from "#lib/auth/handleResolver.ts";
const answering = (did: string): HandleResolver => ({ resolve: vi.fn(async () => did as `did:plc:${string}`)});
const refusing = (message: string): HandleResolver => ({ resolve: vi.fn(async () => { throw new Error(message); })});
describe("handleResolverUrls", () => { test.each([ [undefined, []], ["", []], ["https://pds.test/", ["https://pds.test"]], ["https://tranquil.test, https://pds.test/", ["https://tranquil.test", "https://pds.test"]] ])("reads %j", (raw, expected) => { expect(handleResolverUrls(raw)).toEqual(expected); });});
describe("handleResolverFor without urls", () => { const bobbinUrl = () => "https://bobbin.test"; afterEach(() => vi.unstubAllGlobals());
const network = (routes: Record<string, () => Response>) => vi.stubGlobal( "fetch", vi.fn(async (input: URL) => { const answer = routes[input.hostname]; if (!answer) throw new TypeError(`unexpected fetch of ${input}`); return answer(); }) );
const notFound = () => new Response("", { status: 404 }); const dns = (Status: number, answers: string[] = []) => () => Response.json({ Status, TC: false, RD: true, RA: true, AD: false, CD: false, Question: [{ name: "_atproto.x", type: 16 }], Answer: answers.map((data) => ({ name: "_atproto.x", type: 16, TTL: 60, data })) });
test("asks the handle's own host for a handle with no dns record", async () => { network({ "cloudflare-dns.com": dns(3), "new.tngl.sh": () => new Response("did:plc:abcdefghijklmnopqrstuvwx\n") }); expect(await handleResolverFor([], bobbinUrl).resolve("new.tngl.sh")).toBe( "did:plc:abcdefghijklmnopqrstuvwx" ); });
test("reads the dns record when the handle's host answers nothing", async () => { network({ "cloudflare-dns.com": dns(0, ["did=did:plc:abcdefghijklmnopqrstuvwx"]), "example.com": notFound }); expect(await handleResolverFor([], bobbinUrl).resolve("example.com")).toBe( "did:plc:abcdefghijklmnopqrstuvwx" ); });
test("asks bobbin when the handle's host hides its answer behind cors", async () => { network({ "cloudflare-dns.com": dns(3), "crashkeys.dev": () => { throw new TypeError("Failed to fetch"); }, "bobbin.test": () => Response.json({ did: "did:plc:abcdefghijklmnopqrstuvwx", handle: "crashkeys.dev", pds: "https://pds.crashkeys.dev" }) }); expect(await handleResolverFor([], bobbinUrl).resolve("crashkeys.dev")).toBe( "did:plc:abcdefghijklmnopqrstuvwx" ); });
test("fails when nobody answers", async () => { network({ "cloudflare-dns.com": dns(3), "nobody.test": notFound, "bobbin.test": () => Response.json({ error: "UpstreamFailed" }, { status: 502 }) }); await expect(handleResolverFor([], bobbinUrl).resolve("nobody.test")).rejects.toThrow(); });});
describe("FallbackHandleResolver", () => { test("takes the first answer without asking the rest", async () => { const later = answering("did:plc:later"); const resolver = new FallbackHandleResolver([answering("did:plc:first"), later]); expect(await resolver.resolve("org.tranquil.test")).toBe("did:plc:first"); expect(later.resolve).not.toHaveBeenCalled(); });
test("falls back when an earlier resolver can't resolve the handle", async () => { const resolver = new FallbackHandleResolver([ refusing("HandleNotFound"), answering("did:plc:alice") ]); expect(await resolver.resolve("alice.pds.test")).toBe("did:plc:alice"); });
test("throws the last failure when nobody can resolve it", async () => { const resolver = new FallbackHandleResolver([refusing("first"), refusing("last")]); await expect(resolver.resolve("nobody.test")).rejects.toThrow("last"); });
test("stops on an aborted signal", async () => { const controller = new AbortController(); controller.abort(); const later = answering("did:plc:later"); const resolver = new FallbackHandleResolver([refusing("aborted"), later]); await expect( resolver.resolve("org.tranquil.test", { signal: controller.signal }) ).rejects.toThrow("aborted"); expect(later.resolve).not.toHaveBeenCalled(); });});