import "@js-temporal/polyfill";
import "urlpattern-polyfill";
globalThis.addEventListener = () => {};
import { U as getTypeId, ot as name, st as version } from "./vocab-C5EUmVTj.mjs";
import { i as RouterError, r as Router } from "./lookup-D1kdVIs5.mjs";
import { t as InboxListenerSet } from "./inbox-BtX2yRj2.mjs";
import { getLogger } from "@logtape/logtape";
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
//#region src/federation/builder.ts
var FederationBuilderImpl = class {
	router;
	actorCallbacks;
	nodeInfoDispatcher;
	webFingerLinksDispatcher;
	objectCallbacks;
	objectTypeIds;
	inboxPath;
	inboxCallbacks;
	outboxCallbacks;
	followingCallbacks;
	followersCallbacks;
	likedCallbacks;
	featuredCallbacks;
	featuredTagsCallbacks;
	inboxListeners;
	inboxErrorHandler;
	sharedInboxKeyDispatcher;
	idempotencyStrategy;
	collectionTypeIds;
	collectionCallbacks;
	/**
	* Symbol registry for unique identification of unnamed symbols.
	*/
	#symbolRegistry = /* @__PURE__ */ new Map();
	constructor() {
		this.router = new Router();
		this.objectCallbacks = {};
		this.objectTypeIds = {};
		this.collectionCallbacks = {};
		this.collectionTypeIds = {};
	}
	async build(options) {
		const { FederationImpl } = await import("./middleware-BmYq8xCJ.mjs");
		const f = new FederationImpl(options);
		const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
		f.router = this.router.clone();
		f.router.trailingSlashInsensitive = trailingSlashInsensitiveValue;
		f._initializeRouter();
		f.actorCallbacks = this.actorCallbacks == null ? void 0 : { ...this.actorCallbacks };
		f.nodeInfoDispatcher = this.nodeInfoDispatcher;
		f.webFingerLinksDispatcher = this.webFingerLinksDispatcher;
		f.objectCallbacks = { ...this.objectCallbacks };
		f.objectTypeIds = { ...this.objectTypeIds };
		f.inboxPath = this.inboxPath;
		f.inboxCallbacks = this.inboxCallbacks == null ? void 0 : { ...this.inboxCallbacks };
		f.outboxCallbacks = this.outboxCallbacks == null ? void 0 : { ...this.outboxCallbacks };
		f.followingCallbacks = this.followingCallbacks == null ? void 0 : { ...this.followingCallbacks };
		f.followersCallbacks = this.followersCallbacks == null ? void 0 : { ...this.followersCallbacks };
		f.likedCallbacks = this.likedCallbacks == null ? void 0 : { ...this.likedCallbacks };
		f.featuredCallbacks = this.featuredCallbacks == null ? void 0 : { ...this.featuredCallbacks };
		f.featuredTagsCallbacks = this.featuredTagsCallbacks == null ? void 0 : { ...this.featuredTagsCallbacks };
		f.inboxListeners = this.inboxListeners?.clone();
		f.inboxErrorHandler = this.inboxErrorHandler;
		f.sharedInboxKeyDispatcher = this.sharedInboxKeyDispatcher;
		f.idempotencyStrategy = this.idempotencyStrategy;
		return f;
	}
	_getTracer() {
		return trace.getTracer(name, version);
	}
	setActorDispatcher(path, dispatcher) {
		if (this.router.has("actor")) throw new RouterError("Actor dispatcher already set.");
		const variables = this.router.add(path, "actor");
		if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for actor dispatcher must have one variable: {identifier}");
		if (variables.has("handle")) getLogger([
			"fedify",
			"federation",
			"actor"
		]).warn("The {{handle}} variable in the actor dispatcher path is deprecated. Use {{identifier}} instead.");
		const callbacks = { dispatcher: async (context, identifier) => {
			const actor = await this._getTracer().startActiveSpan("activitypub.dispatch_actor", {
				kind: SpanKind.SERVER,
				attributes: { "fedify.actor.identifier": identifier }
			}, async (span) => {
				try {
					const actor = await dispatcher(context, identifier);
					span.setAttribute("activitypub.actor.id", (actor?.id ?? context.getActorUri(identifier)).href);
					if (actor == null) span.setStatus({ code: SpanStatusCode.ERROR });
					else span.setAttribute("activitypub.actor.type", getTypeId(actor).href);
					return actor;
				} catch (error) {
					span.setStatus({
						code: SpanStatusCode.ERROR,
						message: String(error)
					});
					throw error;
				} finally {
					span.end();
				}
			});
			if (actor == null) return null;
			const logger = getLogger([
				"fedify",
				"federation",
				"actor"
			]);
			if (actor.id == null) logger.warn("Actor dispatcher returned an actor without an id property.  Set the property with Context.getActorUri(identifier).");
			else if (actor.id.href != context.getActorUri(identifier).href) logger.warn("Actor dispatcher returned an actor with an id property that does not match the actor URI.  Set the property with Context.getActorUri(identifier).");
			if (this.followingCallbacks != null && this.followingCallbacks.dispatcher != null) {
				if (actor.followingId == null) logger.warn("You configured a following collection dispatcher, but the actor does not have a following property.  Set the property with Context.getFollowingUri(identifier).");
				else if (actor.followingId.href != context.getFollowingUri(identifier).href) logger.warn("You configured a following collection dispatcher, but the actor's following property does not match the following collection URI.  Set the property with Context.getFollowingUri(identifier).");
			}
			if (this.followersCallbacks != null && this.followersCallbacks.dispatcher != null) {
				if (actor.followersId == null) logger.warn("You configured a followers collection dispatcher, but the actor does not have a followers property.  Set the property with Context.getFollowersUri(identifier).");
				else if (actor.followersId.href != context.getFollowersUri(identifier).href) logger.warn("You configured a followers collection dispatcher, but the actor's followers property does not match the followers collection URI.  Set the property with Context.getFollowersUri(identifier).");
			}
			if (this.outboxCallbacks != null && this.outboxCallbacks.dispatcher != null) {
				if (actor?.outboxId == null) logger.warn("You configured an outbox collection dispatcher, but the actor does not have an outbox property.  Set the property with Context.getOutboxUri(identifier).");
				else if (actor.outboxId.href != context.getOutboxUri(identifier).href) logger.warn("You configured an outbox collection dispatcher, but the actor's outbox property does not match the outbox collection URI.  Set the property with Context.getOutboxUri(identifier).");
			}
			if (this.likedCallbacks != null && this.likedCallbacks.dispatcher != null) {
				if (actor?.likedId == null) logger.warn("You configured a liked collection dispatcher, but the actor does not have a liked property.  Set the property with Context.getLikedUri(identifier).");
				else if (actor.likedId.href != context.getLikedUri(identifier).href) logger.warn("You configured a liked collection dispatcher, but the actor's liked property does not match the liked collection URI.  Set the property with Context.getLikedUri(identifier).");
			}
			if (this.featuredCallbacks != null && this.featuredCallbacks.dispatcher != null) {
				if (actor?.featuredId == null) logger.warn("You configured a featured collection dispatcher, but the actor does not have a featured property.  Set the property with Context.getFeaturedUri(identifier).");
				else if (actor.featuredId.href != context.getFeaturedUri(identifier).href) logger.warn("You configured a featured collection dispatcher, but the actor's featured property does not match the featured collection URI.  Set the property with Context.getFeaturedUri(identifier).");
			}
			if (this.featuredTagsCallbacks != null && this.featuredTagsCallbacks.dispatcher != null) {
				if (actor?.featuredTagsId == null) logger.warn("You configured a featured tags collection dispatcher, but the actor does not have a featuredTags property.  Set the property with Context.getFeaturedTagsUri(identifier).");
				else if (actor.featuredTagsId.href != context.getFeaturedTagsUri(identifier).href) logger.warn("You configured a featured tags collection dispatcher, but the actor's featuredTags property does not match the featured tags collection URI.  Set the property with Context.getFeaturedTagsUri(identifier).");
			}
			if (this.router.has("inbox")) {
				if (actor.inboxId == null) logger.warn("You configured inbox listeners, but the actor does not have an inbox property.  Set the property with Context.getInboxUri(identifier).");
				else if (actor.inboxId.href != context.getInboxUri(identifier).href) logger.warn("You configured inbox listeners, but the actor's inbox property does not match the inbox URI.  Set the property with Context.getInboxUri(identifier).");
				if (actor.endpoints == null || actor.endpoints.sharedInbox == null) logger.warn("You configured inbox listeners, but the actor does not have a endpoints.sharedInbox property.  Set the property with Context.getInboxUri().");
				else if (actor.endpoints.sharedInbox.href != context.getInboxUri().href) logger.warn("You configured inbox listeners, but the actor's endpoints.sharedInbox property does not match the shared inbox URI.  Set the property with Context.getInboxUri().");
			}
			if (callbacks.keyPairsDispatcher != null) {
				if (actor.publicKeyId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have a publicKey property.  Set the property with Context.getActorKeyPairs(identifier).");
				if (actor.assertionMethodId == null) logger.warn("You configured a key pairs dispatcher, but the actor does not have an assertionMethod property.  Set the property with Context.getActorKeyPairs(identifier).");
			}
			return actor;
		} };
		this.actorCallbacks = callbacks;
		const setters = {
			setKeyPairsDispatcher: (dispatcher) => {
				callbacks.keyPairsDispatcher = (ctx, identifier) => this._getTracer().startActiveSpan("activitypub.dispatch_actor_key_pairs", {
					kind: SpanKind.SERVER,
					attributes: {
						"activitypub.actor.id": ctx.getActorUri(identifier).href,
						"fedify.actor.identifier": identifier
					}
				}, async (span) => {
					try {
						return await dispatcher(ctx, identifier);
					} catch (e) {
						span.setStatus({
							code: SpanStatusCode.ERROR,
							message: String(e)
						});
						throw e;
					} finally {
						span.end();
					}
				});
				return setters;
			},
			mapHandle(mapper) {
				callbacks.handleMapper = mapper;
				return setters;
			},
			mapAlias(mapper) {
				callbacks.aliasMapper = mapper;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setNodeInfoDispatcher(path, dispatcher) {
		if (this.router.has("nodeInfo")) throw new RouterError("NodeInfo dispatcher already set.");
		if (this.router.add(path, "nodeInfo").size !== 0) throw new RouterError("Path for NodeInfo dispatcher must have no variables.");
		this.nodeInfoDispatcher = dispatcher;
	}
	setWebFingerLinksDispatcher(dispatcher) {
		this.webFingerLinksDispatcher = dispatcher;
	}
	setObjectDispatcher(cls, path, dispatcher) {
		const routeName = `object:${cls.typeId.href}`;
		if (this.router.has(routeName)) throw new RouterError(`Object dispatcher for ${cls.name} already set.`);
		const variables = this.router.add(path, routeName);
		if (variables.size < 1) throw new RouterError("Path for object dispatcher must have at least one variable.");
		const callbacks = {
			dispatcher: (ctx, values) => {
				return this._getTracer().startActiveSpan("activitypub.dispatch_object", {
					kind: SpanKind.SERVER,
					attributes: {
						"fedify.object.type": cls.typeId.href,
						...globalThis.Object.fromEntries(globalThis.Object.entries(values).map(([k, v]) => [`fedify.object.values.${k}`, v]))
					}
				}, async (span) => {
					try {
						const object = await dispatcher(ctx, values);
						span.setAttribute("activitypub.object.id", (object?.id ?? ctx.getObjectUri(cls, values)).href);
						if (object == null) span.setStatus({ code: SpanStatusCode.ERROR });
						else span.setAttribute("activitypub.object.type", getTypeId(object).href);
						return object;
					} catch (e) {
						span.setStatus({
							code: SpanStatusCode.ERROR,
							message: String(e)
						});
						throw e;
					} finally {
						span.end();
					}
				});
			},
			parameters: variables
		};
		this.objectCallbacks[cls.typeId.href] = callbacks;
		this.objectTypeIds[cls.typeId.href] = cls;
		const setters = { authorize(predicate) {
			callbacks.authorizePredicate = predicate;
			return setters;
		} };
		return setters;
	}
	setInboxDispatcher(path, dispatcher) {
		if (this.inboxCallbacks != null) throw new RouterError("Inbox dispatcher already set.");
		if (this.router.has("inbox")) {
			if (this.inboxPath !== path) throw new RouterError("Inbox dispatcher path must match inbox listener path.");
		} else {
			const variables = this.router.add(path, "inbox");
			if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for inbox dispatcher must have one variable: {identifier}");
			if (variables.has("handle")) getLogger([
				"fedify",
				"federation",
				"inbox"
			]).warn("The {{handle}} variable in the inbox dispatcher path is deprecated. Use {{identifier}} instead.");
			this.inboxPath = path;
		}
		const callbacks = { dispatcher };
		this.inboxCallbacks = callbacks;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setOutboxDispatcher(path, dispatcher) {
		if (this.router.has("outbox")) throw new RouterError("Outbox dispatcher already set.");
		const variables = this.router.add(path, "outbox");
		if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for outbox dispatcher must have one variable: {identifier}");
		if (variables.has("handle")) getLogger([
			"fedify",
			"federation",
			"outbox"
		]).warn("The {{handle}} variable in the outbox dispatcher path is deprecated. Use {{identifier}} instead.");
		const callbacks = { dispatcher };
		this.outboxCallbacks = callbacks;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setFollowingDispatcher(path, dispatcher) {
		if (this.router.has("following")) throw new RouterError("Following collection dispatcher already set.");
		const variables = this.router.add(path, "following");
		if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for following collection dispatcher must have one variable: {identifier}");
		if (variables.has("handle")) getLogger([
			"fedify",
			"federation",
			"collection"
		]).warn("The {{handle}} variable in the following collection dispatcher path is deprecated. Use {{identifier}} instead.");
		const callbacks = { dispatcher };
		this.followingCallbacks = callbacks;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setFollowersDispatcher(path, dispatcher) {
		if (this.router.has("followers")) throw new RouterError("Followers collection dispatcher already set.");
		const variables = this.router.add(path, "followers");
		if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for followers collection dispatcher must have one variable: {identifier}");
		if (variables.has("handle")) getLogger([
			"fedify",
			"federation",
			"collection"
		]).warn("The {{handle}} variable in the followers collection dispatcher path is deprecated. Use {{identifier}} instead.");
		const callbacks = { dispatcher };
		this.followersCallbacks = callbacks;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setLikedDispatcher(path, dispatcher) {
		if (this.router.has("liked")) throw new RouterError("Liked collection dispatcher already set.");
		const variables = this.router.add(path, "liked");
		if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for liked collection dispatcher must have one variable: {identifier}");
		if (variables.has("handle")) getLogger([
			"fedify",
			"federation",
			"collection"
		]).warn("The {{handle}} variable in the liked collection dispatcher path is deprecated. Use {{identifier}} instead.");
		const callbacks = { dispatcher };
		this.likedCallbacks = callbacks;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setFeaturedDispatcher(path, dispatcher) {
		if (this.router.has("featured")) throw new RouterError("Featured collection dispatcher already set.");
		const variables = this.router.add(path, "featured");
		if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for featured collection dispatcher must have one variable: {identifier}");
		if (variables.has("handle")) getLogger([
			"fedify",
			"federation",
			"collection"
		]).warn("The {{handle}} variable in the featured collection dispatcher path is deprecated. Use {{identifier}} instead.");
		const callbacks = { dispatcher };
		this.featuredCallbacks = callbacks;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setFeaturedTagsDispatcher(path, dispatcher) {
		if (this.router.has("featuredTags")) throw new RouterError("Featured tags collection dispatcher already set.");
		const variables = this.router.add(path, "featuredTags");
		if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for featured tags collection dispatcher must have one variable: {identifier}");
		if (variables.has("handle")) getLogger([
			"fedify",
			"federation",
			"collection"
		]).warn("The {{handle}} variable in the featured tags collection dispatcher path is deprecated. Use {{identifier}} instead.");
		const callbacks = { dispatcher };
		this.featuredTagsCallbacks = callbacks;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	setInboxListeners(inboxPath, sharedInboxPath) {
		if (this.inboxListeners != null) throw new RouterError("Inbox listeners already set.");
		if (this.router.has("inbox")) {
			if (this.inboxPath !== inboxPath) throw new RouterError("Inbox listener path must match inbox dispatcher path.");
		} else {
			const variables = this.router.add(inboxPath, "inbox");
			if (variables.size !== 1 || !(variables.has("identifier") || variables.has("handle"))) throw new RouterError("Path for inbox must have one variable: {identifier}");
			this.inboxPath = inboxPath;
			if (variables.has("handle")) getLogger([
				"fedify",
				"federation",
				"inbox"
			]).warn("The {{handle}} variable in the inbox path is deprecated. Use {{identifier}} instead.");
		}
		if (sharedInboxPath != null) {
			if (this.router.add(sharedInboxPath, "sharedInbox").size !== 0) throw new RouterError("Path for shared inbox must have no variables.");
		}
		const listeners = this.inboxListeners = new InboxListenerSet();
		const setters = {
			on(type, listener) {
				listeners.add(type, listener);
				return setters;
			},
			onError: (handler) => {
				this.inboxErrorHandler = handler;
				return setters;
			},
			setSharedKeyDispatcher: (dispatcher) => {
				this.sharedInboxKeyDispatcher = dispatcher;
				return setters;
			},
			withIdempotency: (strategy) => {
				this.idempotencyStrategy = strategy;
				return setters;
			}
		};
		return setters;
	}
	setCollectionDispatcher(name, itemType, path, dispatcher) {
		return this.#setCustomCollectionDispatcher(name, "collection", itemType, path, dispatcher);
	}
	setOrderedCollectionDispatcher(name, itemType, path, dispatcher) {
		return this.#setCustomCollectionDispatcher(name, "orderedCollection", itemType, path, dispatcher);
	}
	#setCustomCollectionDispatcher(name, collectionType, itemType, path, dispatcher) {
		const strName = String(name);
		const routeName = `${collectionType}:${this.#uniqueCollectionId(name)}`;
		if (this.router.has(routeName)) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
		if (this.collectionCallbacks[name] != null) throw new RouterError(`Collection dispatcher for ${strName} already set.`);
		if (this.router.add(path, routeName).size < 1) throw new RouterError("Path for collection dispatcher must have at least one variable.");
		const callbacks = { dispatcher };
		this.collectionCallbacks[name] = callbacks;
		this.collectionTypeIds[name] = itemType;
		const setters = {
			setCounter(counter) {
				callbacks.counter = counter;
				return setters;
			},
			setFirstCursor(cursor) {
				callbacks.firstCursor = cursor;
				return setters;
			},
			setLastCursor(cursor) {
				callbacks.lastCursor = cursor;
				return setters;
			},
			authorize(predicate) {
				callbacks.authorizePredicate = predicate;
				return setters;
			}
		};
		return setters;
	}
	/**
	* Get the URL path for a custom collection.
	* If the collection is not registered, returns null.
	* @template TParam The parameter names of the requested URL.
	* @param {string | symbol} name The name of the custom collection.
	* @param {TParam} values The values to fill in the URL parameters.
	* @returns {string | null} The URL path for the custom collection, or null if not registered.
	*/
	getCollectionPath(name, values) {
		if (!(name in this.collectionCallbacks)) return null;
		const routeName = this.#uniqueCollectionId(name);
		return this.router.build(`collection:${routeName}`, values) ?? this.router.build(`orderedCollection:${routeName}`, values);
	}
	/**
	* Converts a name (string or symbol) to a unique string identifier.
	* For symbols, generates and caches a UUID if not already present.
	* For strings, returns the string as-is.
	* @param name The name to convert to a unique identifier
	* @returns A unique string identifier
	*/
	#uniqueCollectionId(name) {
		if (typeof name === "string") return name;
		if (!this.#symbolRegistry.has(name)) this.#symbolRegistry.set(name, crypto.randomUUID());
		return this.#symbolRegistry.get(name);
	}
};
/**
* Creates a new {@link FederationBuilder} instance.
* @returns A new {@link FederationBuilder} instance.
* @since 1.6.0
*/
function createFederationBuilder() {
	return new FederationBuilderImpl();
}
//#endregion
export { createFederationBuilder as n, FederationBuilderImpl as t };
