const { Temporal } = require("@js-temporal/polyfill");
const { URLPattern } = require("urlpattern-polyfill");
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_docloader = require("../docloader-BZfjD0Xt.cjs");
const require_actor = require("../actor-DILKT_HU.cjs");
const require_lookup = require("../lookup-BnvWOvmD.cjs");
let _logtape_logtape = require("@logtape/logtape");
let _opentelemetry_api = require("@opentelemetry/api");
let es_toolkit = require("es-toolkit");
//#region src/vocab/handle.ts
/**
* Regular expression to match a fediverse handle in the format `@user@server`
* or `user@server`.  The `user` part can contain alphanumeric characters and
* some special characters except `@`.  The `server` part is all characters
* after the `@` symbol in the middle.
*/
const handleRegexp = /^@?((?:[-A-Za-z0-9._~!$&'()*+,;=]|%[A-Fa-f0-9]{2})+)@([^@]+)$/;
/**
* Parses a fediverse handle in the format `@user@server` or `user@server`.
* The `user` part can contain alphanumeric characters and some special
* characters except `@`.  The `server` part is all characters after the `@`
* symbol in the middle.
*
* @example
* ```typescript
* const handle = parseFediverseHandle("@username@example.com");
* console.log(handle?.username); // "username"
* console.log(handle?.host);     // "example.com"
* ```
*
* @param handle - The fediverse handle string to parse.
* @returns A {@link FediverseHandle} object with `username` and `host`
*          if the input is valid; otherwise `null`.
* @since 1.8.0
*/
function parseFediverseHandle(handle) {
	const match = handleRegexp.exec(handle);
	if (match) return {
		username: match[1],
		host: match[2]
	};
	return null;
}
/**
* Checks if a string is a valid fediverse handle in the format `@user@server`
* or `user@server`.  The `user` part can contain alphanumeric characters and
* some special characters except `@`.  The `server` part is all characters
* after the `@` symbol in the middle.
*
* @example
* ```typescript
* console.log(isFediverseHandle("@username@example.com")); // true
* console.log(isFediverseHandle("username@example.com"));  // true
* console.log(isFediverseHandle("@username@"));            // false
* ```
*
* @param handle - The string to test as a fediverse handle.
* @returns `true` if the string matches the fediverse handle pattern;
*          otherwise `false`.
* @since 1.8.0
*/
function isFediverseHandle(handle) {
	return handleRegexp.test(handle);
}
/**
* Converts a fediverse handle in the format `@user@server` or `user@server`
* to an `acct:` URI, which is a URL-like identifier for ActivityPub actors.
*
* @example
* ```typescript
* const identifier = toAcctUrl("@username@example.com");
* console.log(identifier?.href); // "acct:username@example.com"
* ```
*
* @param handle - The fediverse handle string to convert.
* @returns A `URL` object representing the `acct:` URI if conversion succeeds;
*          otherwise `null`.
* @since 1.8.0
*/
function toAcctUrl(handle) {
	const parsed = parseFediverseHandle(handle);
	if (!parsed) return null;
	return new URL(`acct:${parsed.username}@${parsed.host}`);
}
//#endregion
//#region src/vocab/lookup.ts
const logger = (0, _logtape_logtape.getLogger)([
	"fedify",
	"vocab",
	"lookup"
]);
/**
* Looks up an ActivityStreams object by its URI (including `acct:` URIs)
* or a fediverse handle (e.g., `@user@server` or `user@server`).
*
* @example
* ``` typescript
* // Look up an actor by its fediverse handle:
* await lookupObject("@hongminhee@fosstodon.org");
* // returning a `Person` object.
*
* // A fediverse handle can omit the leading '@':
* await lookupObject("hongminhee@fosstodon.org");
* // returning a `Person` object.
*
* // A `acct:` URI can be used as well:
* await lookupObject("acct:hongminhee@fosstodon.org");
* // returning a `Person` object.
*
* // Look up an object by its URI:
* await lookupObject("https://todon.eu/@hongminhee/112060633798771581");
* // returning a `Note` object.
*
* // It can be a `URL` object as well:
* await lookupObject(new URL("https://todon.eu/@hongminhee/112060633798771581"));
* // returning a `Note` object.
* ```
*
* @param identifier The URI or fediverse handle to look up.
* @param options Lookup options.
* @returns The object, or `null` if not found.
* @since 0.2.0
*/
async function lookupObject(identifier, options = {}) {
	return await (options.tracerProvider ?? _opentelemetry_api.trace.getTracerProvider()).getTracer(require_docloader.name, require_docloader.version).startActiveSpan("activitypub.lookup_object", async (span) => {
		try {
			const result = await lookupObjectInternal(identifier, options);
			if (result == null) span.setStatus({ code: _opentelemetry_api.SpanStatusCode.ERROR });
			else {
				if (result.id != null) span.setAttribute("activitypub.object.id", result.id.href);
				span.setAttribute("activitypub.object.type", require_actor.getTypeId(result).href);
				if (result.replyTargetIds.length > 0) span.setAttribute("activitypub.object.in_reply_to", result.replyTargetIds.map((id) => id.href));
			}
			return result;
		} catch (error) {
			span.setStatus({
				code: _opentelemetry_api.SpanStatusCode.ERROR,
				message: String(error)
			});
			throw error;
		} finally {
			span.end();
		}
	});
}
async function lookupObjectInternal(identifier, options = {}) {
	const documentLoader = options.documentLoader ?? require_docloader.getDocumentLoader({ userAgent: options.userAgent });
	if (typeof identifier === "string") identifier = toAcctUrl(identifier) ?? new URL(identifier);
	let remoteDoc = null;
	if (identifier.protocol === "http:" || identifier.protocol === "https:") try {
		remoteDoc = await documentLoader(identifier.href, { signal: options.signal });
	} catch (error) {
		logger.debug("Failed to fetch remote document:\n{error}", { error });
	}
	if (remoteDoc == null) {
		const jrd = await require_lookup.lookupWebFinger(identifier, {
			userAgent: options.userAgent,
			tracerProvider: options.tracerProvider,
			allowPrivateAddress: "allowPrivateAddress" in options && options.allowPrivateAddress === true,
			signal: options.signal
		});
		if (jrd?.links == null) return null;
		for (const l of jrd.links) {
			if (l.type !== "application/activity+json" && !l.type?.match(/application\/ld\+json;\s*profile="https:\/\/www.w3.org\/ns\/activitystreams"/) || l.rel !== "self" || l.href == null) continue;
			try {
				remoteDoc = await documentLoader(l.href, { signal: options.signal });
				break;
			} catch (error) {
				logger.debug("Failed to fetch remote document:\n{error}", { error });
				continue;
			}
		}
	}
	if (remoteDoc == null) return null;
	let object;
	try {
		object = await require_actor.Object.fromJsonLd(remoteDoc.document, {
			documentLoader,
			contextLoader: options.contextLoader,
			tracerProvider: options.tracerProvider,
			baseUrl: new URL(remoteDoc.documentUrl)
		});
	} catch (error) {
		if (error instanceof TypeError) {
			logger.debug("Failed to parse JSON-LD document: {error}\n{document}", {
				...remoteDoc,
				error
			});
			return null;
		}
		throw error;
	}
	if (options.crossOrigin !== "trust" && object.id != null && object.id.origin !== new URL(remoteDoc.documentUrl).origin) {
		if (options.crossOrigin === "throw") throw new Error(`The object's @id (${object.id.href}) has a different origin than the document URL (${remoteDoc.documentUrl}); refusing to return the object.  If you want to bypass this check and are aware of the security implications, set the crossOrigin option to "trust".`);
		logger.warn("The object's @id ({objectId}) has a different origin than the document URL ({documentUrl}); refusing to return the object.  If you want to bypass this check and are aware of the security implications, set the crossOrigin option to \"trust\".", {
			...remoteDoc,
			objectId: object.id.href
		});
		return null;
	}
	return object;
}
/**
* Traverses a collection, yielding each item in the collection.
* If the collection is paginated, it will fetch the next page
* automatically.
*
* @example
* ``` typescript
* const collection = await lookupObject(collectionUrl);
* if (collection instanceof Collection) {
*   for await (const item of traverseCollection(collection)) {
*     console.log(item.id?.href);
*   }
* }
* ```
*
* @param collection The collection to traverse.
* @param options Options for traversing the collection.
* @returns An async iterable of each item in the collection.
* @since 1.1.0
*/
async function* traverseCollection(collection, options = {}) {
	const interval = Temporal.Duration.from(options.interval ?? { seconds: 0 }).total("millisecond");
	let page = await collection.getFirst(options);
	if (page == null) for await (const item of collection.getItems(options)) yield item;
	else while (page != null) {
		for await (const item of page.getItems(options)) yield item;
		if (interval > 0) await (0, es_toolkit.delay)(interval);
		page = await page.getNext(options);
	}
}
//#endregion
//#region src/vocab/constants.ts
/**
* The special public collection for [public addressing].  *Do not mutate this
* object.*
*
* [public addressing]: https://www.w3.org/TR/activitypub/#public-addressing
*
* @since 0.7.0
*/
const PUBLIC_COLLECTION = new URL("https://www.w3.org/ns/activitystreams#Public");
//#endregion
exports.Accept = require_actor.Accept;
exports.Activity = require_actor.Activity;
exports.Add = require_actor.Add;
exports.Announce = require_actor.Announce;
exports.Application = require_actor.Application;
exports.Arrive = require_actor.Arrive;
exports.Article = require_actor.Article;
exports.Audio = require_actor.Audio;
exports.Block = require_actor.Block;
exports.ChatMessage = require_actor.ChatMessage;
exports.Collection = require_actor.Collection;
exports.CollectionPage = require_actor.CollectionPage;
exports.Create = require_actor.Create;
exports.CryptographicKey = require_actor.CryptographicKey;
exports.DataIntegrityProof = require_actor.DataIntegrityProof;
exports.Delete = require_actor.Delete;
exports.DidService = require_actor.DidService;
exports.Dislike = require_actor.Dislike;
exports.Document = require_actor.Document;
exports.Emoji = require_actor.Emoji;
exports.EmojiReact = require_actor.EmojiReact;
exports.Endpoints = require_actor.Endpoints;
exports.Event = require_actor.Event;
exports.Export = require_actor.Export;
exports.Flag = require_actor.Flag;
exports.Follow = require_actor.Follow;
exports.Group = require_actor.Group;
exports.Hashtag = require_actor.Hashtag;
exports.Ignore = require_actor.Ignore;
exports.Image = require_actor.Image;
exports.IntransitiveActivity = require_actor.IntransitiveActivity;
exports.Invite = require_actor.Invite;
exports.Join = require_actor.Join;
exports.Leave = require_actor.Leave;
exports.Like = require_actor.Like;
exports.Link = require_actor.Link;
exports.Listen = require_actor.Listen;
exports.Mention = require_actor.Mention;
exports.Move = require_actor.Move;
exports.Multikey = require_actor.Multikey;
exports.Note = require_actor.Note;
exports.Object = require_actor.Object;
exports.Offer = require_actor.Offer;
exports.OrderedCollection = require_actor.OrderedCollection;
exports.OrderedCollectionPage = require_actor.OrderedCollectionPage;
exports.Organization = require_actor.Organization;
exports.PUBLIC_COLLECTION = PUBLIC_COLLECTION;
exports.Page = require_actor.Page;
exports.Person = require_actor.Person;
exports.Place = require_actor.Place;
exports.Profile = require_actor.Profile;
exports.PropertyValue = require_actor.PropertyValue;
exports.Question = require_actor.Question;
exports.Read = require_actor.Read;
exports.Reject = require_actor.Reject;
exports.Relationship = require_actor.Relationship;
exports.Remove = require_actor.Remove;
exports.Service = require_actor.Service;
exports.Source = require_actor.Source;
exports.TentativeAccept = require_actor.TentativeAccept;
exports.TentativeReject = require_actor.TentativeReject;
exports.Tombstone = require_actor.Tombstone;
exports.Travel = require_actor.Travel;
exports.Undo = require_actor.Undo;
exports.Update = require_actor.Update;
exports.Video = require_actor.Video;
exports.View = require_actor.View;
exports.getActorClassByTypeName = require_actor.getActorClassByTypeName;
exports.getActorHandle = require_actor.getActorHandle;
exports.getActorTypeName = require_actor.getActorTypeName;
exports.getTypeId = require_actor.getTypeId;
exports.isActor = require_actor.isActor;
exports.isFediverseHandle = isFediverseHandle;
exports.lookupObject = lookupObject;
exports.normalizeActorHandle = require_actor.normalizeActorHandle;
exports.parseFediverseHandle = parseFediverseHandle;
exports.toAcctUrl = toAcctUrl;
exports.traverseCollection = traverseCollection;
