
      import { Temporal } from "@js-temporal/polyfill";
      import { URLPattern } from "urlpattern-polyfill";
      globalThis.addEventListener = () => {};
    
import { FetchError, UrlError, contexts_default, deno_default, getDocumentLoader, getUserAgent, kvCache } from "../type-BSR-vRXo.js";
import { assertEquals } from "../assert_equals-DSbWqCm3.js";
import "../assert-MZs1qjMx.js";
import "../assert_instance_of-DHz7EHNU.js";
import { MemoryKvStore } from "../kv-CRZrzyXm.js";
import "../lookup-q8DeFAjR.js";
import { mockDocumentLoader, test } from "../testing-Cqwzq9nj.js";
import "../std__assert-X-_kMxKM.js";
import { assertRejects } from "../assert_rejects-DiIiJbZn.js";
import "../assert_is_error-BPGph1Jx.js";
import "../assert_not_equals-f3m3epl3.js";
import { assertThrows } from "../assert_throws-BOO88avQ.js";
import { esm_default } from "../esm-CIFbziGC.js";
import process from "node:process";

//#region src/runtime/docloader.test.ts
test("new FetchError()", () => {
	const e = new FetchError("https://example.com/", "An error message.");
	assertEquals(e.name, "FetchError");
	assertEquals(e.url, new URL("https://example.com/"));
	assertEquals(e.message, "https://example.com/: An error message.");
	const e2 = new FetchError(new URL("https://example.org/"));
	assertEquals(e2.url, new URL("https://example.org/"));
	assertEquals(e2.message, "https://example.org/");
});
test("getDocumentLoader()", async (t) => {
	const fetchDocumentLoader = getDocumentLoader();
	esm_default.spyGlobal();
	esm_default.get("https://example.com/object", { body: {
		"@context": "https://www.w3.org/ns/activitystreams",
		id: "https://example.com/object",
		name: "Fetched object",
		type: "Object"
	} });
	await t.step("ok", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/object"), {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	esm_default.get("https://example.com/link-ctx", {
		body: {
			id: "https://example.com/link-ctx",
			name: "Fetched object",
			type: "Object"
		},
		headers: {
			"Content-Type": "application/activity+json",
			Link: "<https://www.w3.org/ns/activitystreams>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\""
		}
	});
	esm_default.get("https://example.com/link-obj", { headers: {
		"Content-Type": "text/html; charset=utf-8",
		Link: "<https://example.com/object>; rel=\"alternate\"; type=\"application/activity+json\""
	} });
	esm_default.get("https://example.com/link-obj-relative", { headers: {
		"Content-Type": "text/html; charset=utf-8",
		Link: "</object>; rel=\"alternate\"; type=\"application/activity+json\""
	} });
	esm_default.get("https://example.com/obj-w-wrong-link", {
		body: {
			"@context": "https://www.w3.org/ns/activitystreams",
			id: "https://example.com/obj-w-wrong-link",
			name: "Fetched object",
			type: "Object"
		},
		headers: {
			"Content-Type": "text/html; charset=utf-8",
			Link: "<https://example.com/object>; rel=\"alternate\"; type=\"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"\""
		}
	});
	await t.step("Link header", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/link-ctx"), {
			contextUrl: "https://www.w3.org/ns/activitystreams",
			documentUrl: "https://example.com/link-ctx",
			document: {
				id: "https://example.com/link-ctx",
				name: "Fetched object",
				type: "Object"
			}
		});
		assertEquals(await fetchDocumentLoader("https://example.com/link-obj"), {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	await t.step("Link header relative url", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/link-ctx"), {
			contextUrl: "https://www.w3.org/ns/activitystreams",
			documentUrl: "https://example.com/link-ctx",
			document: {
				id: "https://example.com/link-ctx",
				name: "Fetched object",
				type: "Object"
			}
		});
		assertEquals(await fetchDocumentLoader("https://example.com/link-obj-relative"), {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	await t.step("wrong Link header syntax", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/obj-w-wrong-link"), {
			contextUrl: null,
			documentUrl: "https://example.com/obj-w-wrong-link",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/obj-w-wrong-link",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	esm_default.get("https://example.com/html-link", {
		body: `<html>
        <head>
          <meta charset=utf-8>
          <link
            rel=alternate
            type='application/activity+json'
            href="https://example.com/object">
        </head>
      </html>`,
		headers: { "Content-Type": "text/html; charset=utf-8" }
	});
	await t.step("HTML <link>", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/html-link"), {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	esm_default.get("https://example.com/xhtml-link", {
		body: `<html>
        <head>
          <meta charset="utf-8" />
          <link
            rel=alternate
            type="application/activity+json"
            href="https://example.com/object" />
        </head>
      </html>`,
		headers: { "Content-Type": "application/xhtml+xml; charset=utf-8" }
	});
	await t.step("XHTML <link>", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/xhtml-link"), {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	esm_default.get("https://example.com/html-a", {
		body: `<html>
        <head>
          <meta charset=utf-8>
        </head>
        <body>
          <a
            rel=alternate
            type=application/activity+json
            href=https://example.com/object>test</a>
        </body>
      </html>`,
		headers: { "Content-Type": "text/html; charset=utf-8" }
	});
	await t.step("HTML <a>", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/html-a"), {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	esm_default.get("https://example.com/wrong-content-type", {
		body: {
			"@context": "https://www.w3.org/ns/activitystreams",
			id: "https://example.com/wrong-content-type",
			name: "Fetched object",
			type: "Object"
		},
		headers: { "Content-Type": "text/html; charset=utf-8" }
	});
	await t.step("Wrong Content-Type", async () => {
		assertEquals(await fetchDocumentLoader("https://example.com/wrong-content-type"), {
			contextUrl: null,
			documentUrl: "https://example.com/wrong-content-type",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/wrong-content-type",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	esm_default.get("https://example.com/404", { status: 404 });
	await t.step("not ok", async () => {
		await assertRejects(() => fetchDocumentLoader("https://example.com/404"), FetchError, "HTTP 404: https://example.com/404");
	});
	await t.step("preloaded contexts", async () => {
		for (const [url, document] of Object.entries(contexts_default)) assertEquals(await fetchDocumentLoader(url), {
			contextUrl: null,
			documentUrl: url,
			document
		});
	});
	await t.step("deny non-HTTP/HTTPS", async () => {
		await assertRejects(() => fetchDocumentLoader("ftp://localhost"), UrlError);
	});
	esm_default.get("https://example.com/localhost-redirect", {
		status: 302,
		headers: { Location: "https://localhost/object" }
	});
	esm_default.get("https://example.com/localhost-link", {
		body: `<html>
        <head>
          <meta charset=utf-8>
          <link
            rel=alternate
            type='application/activity+json'
            href="https://localhost/object">
        </head>
      </html>`,
		headers: { "Content-Type": "text/html; charset=utf-8" }
	});
	esm_default.get("https://localhost/object", { body: {
		"@context": "https://www.w3.org/ns/activitystreams",
		id: "https://localhost/object",
		name: "Fetched object",
		type: "Object"
	} });
	await t.step("allowPrivateAddress: false", async () => {
		await assertRejects(() => fetchDocumentLoader("https://localhost/object"), UrlError);
		await assertRejects(() => fetchDocumentLoader("https://example.com/localhost-redirect"), UrlError);
		await assertRejects(() => fetchDocumentLoader("https://example.com/localhost-link"), UrlError);
	});
	const fetchDocumentLoader2 = getDocumentLoader({ allowPrivateAddress: true });
	await t.step("allowPrivateAddress: true", async () => {
		const expected = {
			contextUrl: null,
			documentUrl: "https://localhost/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://localhost/object",
				name: "Fetched object",
				type: "Object"
			}
		};
		assertEquals(await fetchDocumentLoader2("https://localhost/object"), expected);
		assertEquals(await fetchDocumentLoader2("https://example.com/localhost-redirect"), expected);
		assertEquals(await fetchDocumentLoader2("https://example.com/localhost-link"), expected);
	});
	esm_default.hardReset();
});
test("kvCache()", async (t) => {
	const kv = new MemoryKvStore();
	await t.step("cached", async () => {
		const loader = kvCache({
			kv,
			loader: mockDocumentLoader,
			rules: [
				["https://example.org/", Temporal.Duration.from({ days: 1 })],
				[new URL("https://example.net/"), Temporal.Duration.from({ days: 1 })],
				[new URLPattern("https://example.com/*"), Temporal.Duration.from({ days: 30 })]
			],
			prefix: ["_test", "cached"]
		});
		const result = await loader("https://example.com/object");
		assertEquals(result, {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
		const cache = await kv.get([
			"_test",
			"cached",
			"https://example.com/object"
		]);
		assertEquals(cache, result);
		await kv.set([
			"_test",
			"cached",
			"https://example.org/"
		], {
			contextUrl: null,
			documentUrl: "https://example.org/",
			document: { "id": "https://example.org/" }
		});
		const result2 = await loader("https://example.org/");
		assertEquals(result2, {
			contextUrl: null,
			documentUrl: "https://example.org/",
			document: { "id": "https://example.org/" }
		});
		await kv.set([
			"_test",
			"cached",
			"https://example.net/"
		], {
			contextUrl: null,
			documentUrl: "https://example.net/",
			document: { "id": "https://example.net/" }
		});
		const result3 = await loader("https://example.net/");
		assertEquals(result3, {
			contextUrl: null,
			documentUrl: "https://example.net/",
			document: { "id": "https://example.net/" }
		});
	});
	await t.step("not cached", async () => {
		const loader = kvCache({
			kv,
			loader: mockDocumentLoader,
			rules: [],
			prefix: ["_test", "not cached"]
		});
		const result = await loader("https://example.com/object");
		assertEquals(result, {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
		const cache = await kv.get([
			"test2",
			"not cached",
			"https://example.com/object"
		]);
		assertEquals(cache, void 0);
	});
	await t.step("maximum cache duration", () => {
		assertThrows(() => kvCache({
			kv,
			loader: mockDocumentLoader,
			rules: [["https://example.com/", Temporal.Duration.from({
				days: 30,
				seconds: 1
			})]]
		}), TypeError, "The maximum cache duration is 30 days");
		assertThrows(() => kvCache({
			kv,
			loader: mockDocumentLoader,
			rules: [[new URLPattern("https://example.com/*"), Temporal.Duration.from({
				days: 30,
				seconds: 1
			})]]
		}), TypeError, "The maximum cache duration is 30 days");
	});
	await t.step("on kv store exception", async () => {
		class KvStoreThrowsException {
			get(_key) {
				throw new Error("Failed to get key");
			}
			set(_key, _value, _options) {
				throw new Error("Failed to set key");
			}
			delete(_key) {
				throw new Error("Failed to delete key");
			}
		}
		const loader = kvCache({
			kv: new KvStoreThrowsException(),
			loader: mockDocumentLoader,
			rules: [
				["https://example.org/", Temporal.Duration.from({ days: 1 })],
				[new URL("https://example.net/"), Temporal.Duration.from({ days: 1 })],
				[new URLPattern("https://example.com/*"), Temporal.Duration.from({ days: 30 })]
			],
			prefix: ["_test", "not cached"]
		});
		const result = await loader("https://example.com/object");
		assertEquals(result, {
			contextUrl: null,
			documentUrl: "https://example.com/object",
			document: {
				"@context": "https://www.w3.org/ns/activitystreams",
				id: "https://example.com/object",
				name: "Fetched object",
				type: "Object"
			}
		});
	});
	await t.step("preloaded contexts bypass cache", async () => {
		const kv$1 = new MemoryKvStore();
		let loaderCalled = false;
		const mockLoader = (url) => {
			loaderCalled = true;
			return Promise.resolve({
				contextUrl: null,
				documentUrl: url,
				document: { "mock": "document" }
			});
		};
		const loader = kvCache({
			kv: kv$1,
			loader: mockLoader,
			prefix: ["_test", "preloaded"]
		});
		const activityStreamsUrl = "https://www.w3.org/ns/activitystreams";
		loaderCalled = false;
		const result = await loader(activityStreamsUrl);
		assertEquals(result, {
			contextUrl: null,
			documentUrl: activityStreamsUrl,
			document: contexts_default[activityStreamsUrl]
		});
		assertEquals(loaderCalled, false, "Loader should not be called for preloaded contexts");
		const cachedValue = await kv$1.get([
			"_test",
			"preloaded",
			activityStreamsUrl
		]);
		assertEquals(cachedValue, void 0, "Preloaded contexts should not be cached in KV store");
		const securityUrl = "https://w3id.org/security/v1";
		loaderCalled = false;
		const result2 = await loader(securityUrl);
		assertEquals(result2, {
			contextUrl: null,
			documentUrl: securityUrl,
			document: contexts_default[securityUrl]
		});
		assertEquals(loaderCalled, false, "Loader should not be called for preloaded contexts");
		const nonPreloadedUrl = "https://example.com/not-preloaded";
		loaderCalled = false;
		const result3 = await loader(nonPreloadedUrl);
		assertEquals(result3, {
			contextUrl: null,
			documentUrl: nonPreloadedUrl,
			document: { "mock": "document" }
		});
		assertEquals(loaderCalled, true, "Loader should be called for non-preloaded URLs");
		const cachedValue2 = await kv$1.get([
			"_test",
			"preloaded",
			nonPreloadedUrl
		]);
		assertEquals(cachedValue2, result3, "Non-preloaded URLs should be cached");
	});
});
test("getUserAgent()", () => {
	if ("Deno" in globalThis) {
		assertEquals(getUserAgent(), `Fedify/${deno_default.version} (Deno/${Deno.version.deno})`);
		assertEquals(getUserAgent({ software: "MyApp/1.0.0" }), `MyApp/1.0.0 (Fedify/${deno_default.version}; Deno/${Deno.version.deno})`);
		assertEquals(getUserAgent({ url: "https://example.com/" }), `Fedify/${deno_default.version} (Deno/${Deno.version.deno}; +https://example.com/)`);
		assertEquals(getUserAgent({
			software: "MyApp/1.0.0",
			url: new URL("https://example.com/")
		}), `MyApp/1.0.0 (Fedify/${deno_default.version}; Deno/${Deno.version.deno}; +https://example.com/)`);
	} else if ("Bun" in globalThis) {
		assertEquals(getUserAgent(), `Fedify/${deno_default.version} (Bun/${Bun.version})`);
		assertEquals(getUserAgent({ software: "MyApp/1.0.0" }), `MyApp/1.0.0 (Fedify/${deno_default.version}; Bun/${Bun.version})`);
		assertEquals(getUserAgent({ url: "https://example.com/" }), `Fedify/${deno_default.version} (Bun/${Bun.version}; +https://example.com/)`);
		assertEquals(getUserAgent({
			software: "MyApp/1.0.0",
			url: new URL("https://example.com/")
		}), `MyApp/1.0.0 (Fedify/${deno_default.version}; Bun/${Bun.version}; +https://example.com/)`);
	} else if (navigator.userAgent === "Cloudflare-Workers") {
		assertEquals(getUserAgent(), `Fedify/${deno_default.version} (Cloudflare-Workers)`);
		assertEquals(getUserAgent({ software: "MyApp/1.0.0" }), `MyApp/1.0.0 (Fedify/${deno_default.version}; Cloudflare-Workers)`);
		assertEquals(getUserAgent({ url: "https://example.com/" }), `Fedify/${deno_default.version} (Cloudflare-Workers; +https://example.com/)`);
		assertEquals(getUserAgent({
			software: "MyApp/1.0.0",
			url: new URL("https://example.com/")
		}), `MyApp/1.0.0 (Fedify/${deno_default.version}; Cloudflare-Workers; +https://example.com/)`);
	} else {
		assertEquals(getUserAgent(), `Fedify/${deno_default.version} (Node.js/${process.versions.node})`);
		assertEquals(getUserAgent({ software: "MyApp/1.0.0" }), `MyApp/1.0.0 (Fedify/${deno_default.version}; Node.js/${process.versions.node})`);
		assertEquals(getUserAgent({ url: "https://example.com/" }), `Fedify/${deno_default.version} (Node.js/${process.versions.node}; +https://example.com/)`);
		assertEquals(getUserAgent({
			software: "MyApp/1.0.0",
			url: new URL("https://example.com/")
		}), `MyApp/1.0.0 (Fedify/${deno_default.version}; Node.js/${process.versions.node}; +https://example.com/)`);
	}
});

//#endregion