import { n as PLUGIN_CAPABILITIES, t as HOOK_NAMES } from "../manifest-schema-BHlgZM1W.mjs";
import { a as normalizeCapabilities } from "../types-DROWRxYV.mjs";

//#region src/plugins/adapt-sandbox-entry.ts
/**
* Default hook configuration values
*/
const DEFAULT_PRIORITY = 100;
const DEFAULT_TIMEOUT = 5e3;
const DEFAULT_ERROR_POLICY = "abort";
/**
* Check if a hook entry is the config form (has a `handler` property).
*/
function isHookConfig(entry) {
	return typeof entry === "object" && entry !== null && "handler" in entry;
}
/**
* Resolve a single hook entry to a ResolvedHook.
*
* Sandboxed-format hooks use the standard two-arg convention:
*   handler(event, ctx)
*
* The HookPipeline dispatch methods also call handlers with (event, ctx),
* so the handler is compatible as-is — we just normalise the
* surrounding config (priority, timeout, etc.) to its defaults.
*/
function resolveSandboxedHook(entry, pluginId) {
	if (isHookConfig(entry)) return {
		priority: entry.priority ?? DEFAULT_PRIORITY,
		timeout: entry.timeout ?? DEFAULT_TIMEOUT,
		dependencies: entry.dependencies ?? [],
		errorPolicy: entry.errorPolicy ?? DEFAULT_ERROR_POLICY,
		exclusive: entry.exclusive ?? false,
		handler: entry.handler,
		pluginId
	};
	return {
		priority: DEFAULT_PRIORITY,
		timeout: DEFAULT_TIMEOUT,
		dependencies: [],
		errorPolicy: DEFAULT_ERROR_POLICY,
		exclusive: false,
		handler: entry,
		pluginId
	};
}
/**
* Normalise a `RouteEntry` (bare handler or `{ handler, public?, input? }`
* config) to the config form. The `input` schema is intentionally typed
* `unknown` in `RouteEntry` — sandboxed plugins describe it loosely
* because the strict `z.ZodType<TInput>` constraint of the runtime's
* `PluginRoute` only narrows once the route is wired into the router.
* The wider type flows through to the runtime which validates at
* invocation time.
*/
function normalizeRouteEntry(entry) {
	if (typeof entry === "function") return { handler: entry };
	return {
		handler: entry.handler,
		public: entry.public,
		input: entry.input
	};
}
const VALID_CAPABILITIES_SET = new Set(PLUGIN_CAPABILITIES);
const VALID_HOOK_NAMES_SET = new Set(HOOK_NAMES);
/**
* Adapt a sandboxed plugin's default export into a ResolvedPlugin.
*
* This is the in-process side of sandboxed-format plugins: it takes
* the `{ hooks, routes }` default export of a sandboxed plugin and
* produces a `ResolvedPlugin` that enters the HookPipeline alongside
* native plugins. The descriptor supplies identity (id, version) and
* the trust contract (capabilities, allowedHosts, storage); the
* definition supplies behaviour.
*
* @param definition - The plugin's default export (matching `SandboxedPlugin` from `emdash/plugin`).
* @param descriptor - The plugin descriptor with id, version, capabilities, etc.
* @returns A ResolvedPlugin compatible with HookPipeline.
*/
function adaptSandboxEntry(definition, descriptor) {
	const pluginId = descriptor.id;
	const version = descriptor.version;
	if (typeof definition !== "object" || definition === null || Array.isArray(definition)) throw new Error(`Plugin "${pluginId}" default export must be an object with \`hooks\` and/or \`routes\` (got ${Array.isArray(definition) ? "array" : typeof definition}). Did you forget \`export default {...} satisfies SandboxedPlugin\`?`);
	const resolvedHooks = {};
	if (definition.hooks) {
		const hookMap = definition.hooks;
		for (const [hookName, entry] of Object.entries(hookMap)) {
			if (!VALID_HOOK_NAMES_SET.has(hookName)) throw new Error(`Plugin "${pluginId}" declares unknown hook "${hookName}". Valid hooks: ${[...VALID_HOOK_NAMES_SET].join(", ")}`);
			resolvedHooks[hookName] = resolveSandboxedHook(entry, pluginId);
		}
	}
	const resolvedRoutes = {};
	if (definition.routes) for (const [routeName, rawEntry] of Object.entries(definition.routes)) {
		const { handler, public: publicFlag, input: inputSchema } = normalizeRouteEntry(rawEntry);
		resolvedRoutes[routeName] = {
			input: inputSchema,
			public: publicFlag,
			handler: async (ctx) => {
				const headers = {};
				ctx.request.headers.forEach((value, name) => {
					headers[name] = value;
				});
				const requestShape = {
					url: ctx.request.url,
					method: ctx.request.method,
					headers
				};
				const routeCtx = {
					input: ctx.input,
					request: requestShape,
					requestMeta: ctx.requestMeta
				};
				const { input: _, request: __, requestMeta: ___, ...pluginCtx } = ctx;
				return handler(routeCtx, pluginCtx);
			}
		};
	}
	const rawCapabilities = descriptor.capabilities ?? [];
	for (const cap of rawCapabilities) if (!VALID_CAPABILITIES_SET.has(cap)) throw new Error(`Invalid capability "${cap}" in plugin "${pluginId}". Valid capabilities: ${[...VALID_CAPABILITIES_SET].join(", ")}`);
	const capabilities = normalizeCapabilities(rawCapabilities);
	const allowedHosts = descriptor.allowedHosts ?? [];
	if (capabilities.includes("content:write") && !capabilities.includes("content:read")) capabilities.push("content:read");
	if (capabilities.includes("media:write") && !capabilities.includes("media:read")) capabilities.push("media:read");
	if (capabilities.includes("network:request:unrestricted") && !capabilities.includes("network:request")) capabilities.push("network:request");
	const rawStorage = descriptor.storage ?? {};
	const storage = {};
	for (const [name, config] of Object.entries(rawStorage)) storage[name] = {
		indexes: config.indexes ?? [],
		uniqueIndexes: config.uniqueIndexes
	};
	const admin = {};
	if (descriptor.adminPages) admin.pages = descriptor.adminPages;
	if (descriptor.adminWidgets) admin.widgets = descriptor.adminWidgets;
	if (descriptor.portableTextBlocks) admin.portableTextBlocks = descriptor.portableTextBlocks;
	if (descriptor.fieldWidgets) admin.fieldWidgets = descriptor.fieldWidgets;
	return {
		id: pluginId,
		version,
		capabilities,
		allowedHosts,
		storage,
		hooks: resolvedHooks,
		routes: resolvedRoutes,
		admin
	};
}

//#endregion
export { adaptSandboxEntry };
//# sourceMappingURL=adapt-sandbox-entry.mjs.map