//#region src/client/transport.ts
/**
* Transport layer for the EmDash client.
*
* Implements a composable interceptor pipeline that modifies requests
* and responses. The client calls `transport.fetch(request)` — everything
* else (auth, CSRF, retry) is handled by interceptors.
*/
const COOKIE_NAME_VALUE_PATTERN = /^([^;]+)/;
function baseFetch(request) {
	return globalThis.fetch(request);
}
/**
* Creates a fetch function that runs requests through an interceptor pipeline.
*/
function createTransport(options = {}) {
	const interceptors = options.interceptors ?? [];
	let chain = baseFetch;
	for (let i = interceptors.length - 1; i >= 0; i--) {
		const interceptor = interceptors[i];
		const next = chain;
		chain = (req) => interceptor(req, next);
	}
	return { fetch: chain };
}
/**
* Adds X-EmDash-Request: 1 and Origin headers to mutation requests
* (POST, PUT, DELETE). The custom header satisfies EmDash's CSRF check;
* the Origin header satisfies Astro's built-in origin verification which
* rejects server-side POST requests that lack a matching Origin.
*/
function csrfInterceptor() {
	const MUTATION_METHODS = new Set([
		"POST",
		"PUT",
		"DELETE",
		"PATCH"
	]);
	return (request, next) => {
		if (MUTATION_METHODS.has(request.method)) {
			const headers = new Headers(request.headers);
			headers.set("X-EmDash-Request", "1");
			if (!headers.has("Origin")) {
				const url = new URL(request.url);
				headers.set("Origin", url.origin);
			}
			return next(new Request(request, { headers }));
		}
		return next(request);
	};
}
/**
* Adds Authorization: Bearer header from a static token.
*/
function tokenInterceptor(token) {
	return (request, next) => {
		const headers = new Headers(request.headers);
		headers.set("Authorization", `Bearer ${token}`);
		return next(new Request(request, { headers }));
	};
}
/**
* Dev bypass interceptor. Calls the dev-bypass endpoint on first request
* to establish a session, then forwards the session cookie on subsequent
* requests.
*/
function devBypassInterceptor(baseUrl) {
	let sessionCookie = null;
	let initializing = null;
	async function init() {
		const bypassUrl = new URL("/_emdash/api/auth/dev-bypass", baseUrl);
		const res = await globalThis.fetch(bypassUrl, { redirect: "manual" });
		const setCookie = res.headers.get("set-cookie");
		if (setCookie) {
			const match = setCookie.match(COOKIE_NAME_VALUE_PATTERN);
			if (match) sessionCookie = match[1];
		}
		if (res.body) await res.text().catch(() => {});
	}
	return async (request, next) => {
		if (!sessionCookie) {
			if (!initializing) initializing = init();
			await initializing;
		}
		if (sessionCookie) {
			const headers = new Headers(request.headers);
			const existing = headers.get("cookie");
			headers.set("cookie", existing ? `${existing}; ${sessionCookie}` : sessionCookie);
			return next(new Request(request, { headers }));
		}
		return next(request);
	};
}
/**
* Auto-refreshes expired OAuth tokens on 401 responses.
* Requires a refresh token and the token endpoint URL.
*/
function refreshInterceptor(options) {
	let refreshing = null;
	async function refresh() {
		const res = await globalThis.fetch(options.tokenEndpoint, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({
				grant_type: "refresh_token",
				refresh_token: options.refreshToken
			})
		});
		if (!res.ok) return null;
		const json = await res.json();
		const tokenData = json.data && typeof json.data === "object" && "access_token" in json.data ? json.data : json;
		const expiresAt = tokenData.expires_in ? new Date(Date.now() + tokenData.expires_in * 1e3).toISOString() : new Date(Date.now() + 36e5).toISOString();
		if (options.onTokenRefreshed) options.onTokenRefreshed(tokenData.access_token, tokenData.refresh_token ?? options.refreshToken, expiresAt);
		return tokenData.access_token;
	}
	return async (request, next) => {
		const response = await next(request);
		if (response.status === 401) {
			if (!refreshing) refreshing = refresh().finally(() => {
				refreshing = null;
			});
			const newToken = await refreshing;
			if (newToken) {
				const headers = new Headers(request.headers);
				headers.set("Authorization", `Bearer ${newToken}`);
				return next(new Request(request, { headers }));
			}
		}
		return response;
	};
}

//#endregion
export { tokenInterceptor as a, refreshInterceptor as i, csrfInterceptor as n, devBypassInterceptor as r, createTransport as t };
//# sourceMappingURL=transport-DPefPMcz.mjs.map