import "@js-temporal/polyfill";
import "urlpattern-polyfill";
globalThis.addEventListener = () => {};
import { C as Person, _ as Note, i as Collection, v as Object$1 } from "../vocab-C5EUmVTj.mjs";
import { n as traverseCollection, t as lookupObject } from "../lookup-D1kdVIs5.mjs";
import { a as mockDocumentLoader, t as test } from "../testing-BQeTO4ss.mjs";
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
import "../std__assert-2v7gYiZp.mjs";
import { t as assertRejects } from "../assert_rejects-CJC9ThS-.mjs";
import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
import { t as assert } from "../assert-DikXweDx.mjs";
import { t as esm_default } from "../esm-D-9VAGKG.mjs";
import { t as createTestTracerProvider } from "../otel-D00WjYJ1.mjs";
import { deepStrictEqual } from "node:assert";
//#region src/vocab/lookup.test.ts
test("lookupObject()", {
	sanitizeResources: false,
	sanitizeOps: false
}, async (t) => {
	esm_default.spyGlobal();
	esm_default.get("begin:https://example.com/.well-known/webfinger", {
		subject: "acct:johndoe@example.com",
		links: [
			{
				rel: "alternate",
				href: "https://example.com/object",
				type: "application/activity+json"
			},
			{
				rel: "self",
				href: "https://example.com/html/person",
				type: "text/html"
			},
			{
				rel: "self",
				href: "https://example.com/person",
				type: "application/activity+json"
			}
		]
	});
	const options = {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	};
	await t.step("actor", async () => {
		const person = await lookupObject("@johndoe@example.com", options);
		assertInstanceOf(person, Person);
		assertEquals(person.id, new URL("https://example.com/person"));
		assertEquals(person.name, "John Doe");
		assertEquals(await lookupObject("johndoe@example.com", options), person);
		assertEquals(await lookupObject("acct:johndoe@example.com", options), person);
	});
	await t.step("object", async () => {
		const object = await lookupObject("https://example.com/object", options);
		assertInstanceOf(object, Object$1);
		assertEquals(object, new Object$1({
			id: new URL("https://example.com/object"),
			name: "Fetched object"
		}));
		const person = await lookupObject("https://example.com/hong-gildong", options);
		assertInstanceOf(person, Person);
		assertEquals(person, new Person({
			id: new URL("https://example.com/hong-gildong"),
			name: "Hong Gildong"
		}));
	});
	esm_default.removeRoutes();
	esm_default.get("begin:https://example.com/.well-known/webfinger", {
		subject: "acct:janedoe@example.com",
		links: [{
			rel: "self",
			href: "https://example.com/404",
			type: "application/activity+json"
		}]
	});
	await t.step("not found", async () => {
		assertEquals(await lookupObject("janedoe@example.com", options), null);
		assertEquals(await lookupObject("https://example.com/404", options), null);
	});
	esm_default.removeRoutes();
	esm_default.get("begin:https://example.com/.well-known/webfinger", () => new Promise((resolve) => {
		setTimeout(() => {
			resolve({
				subject: "acct:johndoe@example.com",
				links: [{
					rel: "self",
					href: "https://example.com/person",
					type: "application/activity+json"
				}]
			});
		}, 1e3);
	}));
	await t.step("request cancellation", async () => {
		const controller = new AbortController();
		const promise = lookupObject("johndoe@example.com", {
			...options,
			signal: controller.signal
		});
		controller.abort();
		assertEquals(await promise, null);
	});
	esm_default.removeRoutes();
	esm_default.get("begin:https://example.com/.well-known/webfinger", {
		subject: "acct:johndoe@example.com",
		links: [{
			rel: "self",
			href: "https://example.com/person",
			type: "application/activity+json"
		}]
	});
	await t.step("successful request with signal", async () => {
		const controller = new AbortController();
		const person = await lookupObject("johndoe@example.com", {
			...options,
			signal: controller.signal
		});
		assertInstanceOf(person, Person);
		assertEquals(person.id, new URL("https://example.com/person"));
	});
	esm_default.removeRoutes();
	esm_default.get("begin:https://example.com/.well-known/webfinger", () => new Promise((resolve) => {
		setTimeout(() => {
			resolve({
				subject: "acct:johndoe@example.com",
				links: [{
					rel: "self",
					href: "https://example.com/person",
					type: "application/activity+json"
				}]
			});
		}, 500);
	}));
	await t.step("cancellation with immediate abort", async () => {
		const controller = new AbortController();
		controller.abort();
		assertEquals(await lookupObject("johndoe@example.com", {
			...options,
			signal: controller.signal
		}), null);
	});
	esm_default.removeRoutes();
	esm_default.get("https://example.com/slow-object", () => new Promise((resolve) => {
		setTimeout(() => {
			resolve({
				status: 200,
				headers: { "Content-Type": "application/activity+json" },
				body: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					content: "Slow response"
				}
			});
		}, 1e3);
	}));
	await t.step("direct object fetch cancellation", async () => {
		const controller = new AbortController();
		const promise = lookupObject("https://example.com/slow-object", {
			contextLoader: mockDocumentLoader,
			signal: controller.signal
		});
		controller.abort();
		assertEquals(await promise, null);
	});
	esm_default.hardReset();
	esm_default.removeRoutes();
});
test("traverseCollection()", {
	sanitizeResources: false,
	sanitizeOps: false
}, async () => {
	const options = {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader
	};
	const collection = await lookupObject("https://example.com/collection", options);
	assertInstanceOf(collection, Collection);
	assertEquals(await Array.fromAsync(traverseCollection(collection, options)), [
		new Note({ content: "This is a simple note" }),
		new Note({ content: "This is another simple note" }),
		new Note({ content: "This is a third simple note" })
	]);
	const pagedCollection = await lookupObject("https://example.com/paged-collection", options);
	assertInstanceOf(pagedCollection, Collection);
	assertEquals(await Array.fromAsync(traverseCollection(pagedCollection, options)), [
		new Note({ content: "This is a simple note" }),
		new Note({ content: "This is another simple note" }),
		new Note({ content: "This is a third simple note" })
	]);
	assertEquals(await Array.fromAsync(traverseCollection(pagedCollection, {
		...options,
		interval: { milliseconds: 250 }
	})), [
		new Note({ content: "This is a simple note" }),
		new Note({ content: "This is another simple note" }),
		new Note({ content: "This is a third simple note" })
	]);
	const inlinePagedCollection = await lookupObject("https://example.com/inline-paged-collection", options);
	assertInstanceOf(inlinePagedCollection, Collection);
	deepStrictEqual(await Array.fromAsync(traverseCollection(inlinePagedCollection, options)), [new Note({ content: "Inline first note" }), new Note({ content: "Inline second note" })]);
});
test("FEP-fe34: lookupObject() cross-origin security", {
	sanitizeResources: false,
	sanitizeOps: false
}, async (t) => {
	await t.step("crossOrigin: ignore (default) - returns null for cross-origin objects", async () => {
		const crossOriginDocumentLoader = async (url) => {
			if (url === "https://example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					id: "https://malicious.com/fake-note",
					content: "This is a spoofed note from a different origin"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		assertEquals(await lookupObject("https://example.com/note", {
			documentLoader: crossOriginDocumentLoader,
			contextLoader: mockDocumentLoader
		}), null);
	});
	await t.step("crossOrigin: throw - throws error for cross-origin objects", async () => {
		const crossOriginDocumentLoader = async (url) => {
			if (url === "https://example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					id: "https://malicious.com/fake-note",
					content: "This is a spoofed note from a different origin"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		await assertRejects(() => lookupObject("https://example.com/note", {
			documentLoader: crossOriginDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "throw"
		}), Error, "The object's @id (https://malicious.com/fake-note) has a different origin than the document URL (https://example.com/note)");
	});
	await t.step("crossOrigin: trust - allows cross-origin objects", async () => {
		const crossOriginDocumentLoader = async (url) => {
			if (url === "https://example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					id: "https://malicious.com/fake-note",
					content: "This is a spoofed note from a different origin"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		const result = await lookupObject("https://example.com/note", {
			documentLoader: crossOriginDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "trust"
		});
		assertInstanceOf(result, Note);
		assertEquals(result.id, new URL("https://malicious.com/fake-note"));
		assertEquals(result.content, "This is a spoofed note from a different origin");
	});
	await t.step("same-origin objects are always trusted", async () => {
		const sameOriginDocumentLoader = async (url) => {
			if (url === "https://example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					id: "https://example.com/note",
					content: "This is a legitimate note from the same origin"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		const result = await lookupObject("https://example.com/note", {
			documentLoader: sameOriginDocumentLoader,
			contextLoader: mockDocumentLoader
		});
		assertInstanceOf(result, Note);
		assertEquals(result.id, new URL("https://example.com/note"));
		assertEquals(result.content, "This is a legitimate note from the same origin");
	});
	await t.step("objects without @id are trusted", async () => {
		const noIdDocumentLoader = async (url) => {
			if (url === "https://example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					content: "This is a note without an ID"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		const result = await lookupObject("https://example.com/note", {
			documentLoader: noIdDocumentLoader,
			contextLoader: mockDocumentLoader
		});
		assertInstanceOf(result, Note);
		assertEquals(result.id, null);
		assertEquals(result.content, "This is a note without an ID");
	});
	await t.step("WebFinger lookup with cross-origin actor URL", async () => {
		esm_default.spyGlobal();
		esm_default.get("begin:https://example.com/.well-known/webfinger", {
			subject: "acct:user@example.com",
			links: [{
				rel: "self",
				href: "https://different-origin.com/actor",
				type: "application/activity+json"
			}]
		});
		const webfingerDocumentLoader = async (url) => {
			if (url === "https://different-origin.com/actor") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Person",
					id: "https://malicious.com/fake-actor",
					name: "Fake Actor"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		assertEquals(await lookupObject("@user@example.com", {
			documentLoader: webfingerDocumentLoader,
			contextLoader: mockDocumentLoader
		}), null);
		await assertRejects(() => lookupObject("@user@example.com", {
			documentLoader: webfingerDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "throw"
		}), Error, "The object's @id (https://malicious.com/fake-actor) has a different origin than the document URL (https://different-origin.com/actor)");
		const result2 = await lookupObject("@user@example.com", {
			documentLoader: webfingerDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "trust"
		});
		assertInstanceOf(result2, Person);
		assertEquals(result2.id, new URL("https://malicious.com/fake-actor"));
		esm_default.removeRoutes();
		esm_default.hardReset();
	});
	await t.step("subdomain same-origin check", async () => {
		const subdomainDocumentLoader = async (url) => {
			if (url === "https://api.example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					id: "https://www.example.com/note",
					content: "Cross-subdomain note"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		assertEquals(await lookupObject("https://api.example.com/note", {
			documentLoader: subdomainDocumentLoader,
			contextLoader: mockDocumentLoader
		}), null);
	});
	await t.step("different port same-origin check", async () => {
		const differentPortDocumentLoader = async (url) => {
			if (url === "https://example.com:8080/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					id: "https://example.com:9090/note",
					content: "Cross-port note"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		assertEquals(await lookupObject("https://example.com:8080/note", {
			documentLoader: differentPortDocumentLoader,
			contextLoader: mockDocumentLoader
		}), null);
	});
	await t.step("protocol difference same-origin check", async () => {
		const differentProtocolDocumentLoader = async (url) => {
			if (url === "https://example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: {
					"@context": "https://www.w3.org/ns/activitystreams",
					type: "Note",
					id: "http://example.com/note",
					content: "Cross-protocol note"
				}
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		assertEquals(await lookupObject("https://example.com/note", {
			documentLoader: differentProtocolDocumentLoader,
			contextLoader: mockDocumentLoader
		}), null);
	});
	await t.step("error handling with crossOrigin throw option", async () => {
		const errorDocumentLoader = async (_url) => {
			throw new Error("Network error");
		};
		assertEquals(await lookupObject("https://example.com/note", {
			documentLoader: errorDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "throw"
		}), null);
	});
	await t.step("malformed JSON handling with cross-origin policy", async () => {
		const malformedJsonDocumentLoader = async (url) => {
			if (url === "https://example.com/note") return {
				documentUrl: url,
				contextUrl: null,
				document: "invalid json"
			};
			throw new Error(`Unexpected URL: ${url}`);
		};
		assertEquals(await lookupObject("https://example.com/note", {
			documentLoader: malformedJsonDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "ignore"
		}), null);
		assertEquals(await lookupObject("https://example.com/note", {
			documentLoader: malformedJsonDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "throw"
		}), null);
		assertEquals(await lookupObject("https://example.com/note", {
			documentLoader: malformedJsonDocumentLoader,
			contextLoader: mockDocumentLoader,
			crossOrigin: "trust"
		}), null);
	});
});
test("lookupObject() records OpenTelemetry span events", async () => {
	const [tracerProvider, exporter] = createTestTracerProvider();
	assertInstanceOf(await lookupObject("https://example.com/object", {
		documentLoader: mockDocumentLoader,
		contextLoader: mockDocumentLoader,
		tracerProvider
	}), Object$1);
	const spans = exporter.getSpans("activitypub.lookup_object");
	assertEquals(spans.length, 1);
	const span = spans[0];
	assertEquals(span.attributes["activitypub.object.id"], "https://example.com/object");
	const events = exporter.getEvents("activitypub.lookup_object", "activitypub.object.fetched");
	assertEquals(events.length, 1);
	const event = events[0];
	assert(event.attributes != null);
	assert(typeof event.attributes["activitypub.object.type"] === "string");
	assert(typeof event.attributes["activitypub.object.json"] === "string");
	assertEquals(JSON.parse(event.attributes["activitypub.object.json"]).id, "https://example.com/object");
});
//#endregion
export {};
