import { a as __exportAll } from "./runner-K8XK101B.mjs";
import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
import { r as requestCached } from "./request-cache-KCNHp_RJ.mjs";
import { t as BylineRepository } from "./byline-Bm8ZgUP9.mjs";
import { n as isMissingTableError } from "./db-errors-CK46D-ly.mjs";
import { a as getDb } from "./loader-CB6YHeul.mjs";
import { i as resolveLocaleChain } from "./resolve-DR3wqMTy.mjs";
import { sql } from "kysely";

//#region src/bylines/index.ts
var bylines_exports = /* @__PURE__ */ __exportAll({
	getByline: () => getByline,
	getBylineBySlug: () => getBylineBySlug,
	getBylinesForEntries: () => getBylinesForEntries,
	getEntriesByByline: () => getEntriesByByline,
	invalidateBylineCache: () => invalidateBylineCache
});
/**
* No-op — kept for API compatibility.
*
* Used to invalidate a worker-lifetime "has any byline?" probe. That
* probe added a query on every cold isolate to save one query on sites
* with zero bylines (i.e. the wrong tradeoff), so we dropped it. The
* batch byline join below returns an empty map for empty sites at the
* same cost as the probe, without the pre-check.
*/
function invalidateBylineCache() {}
/**
* Get a byline by ID.
*
* @example
* ```ts
* import { getByline } from "emdash";
*
* const byline = await getByline("01HXYZ...");
* if (byline) {
*   console.log(byline.displayName);
* }
* ```
*/
async function getByline(id) {
	return new BylineRepository(await getDb()).findById(id);
}
/**
* Get a byline by slug.
*
* Standalone identity lookup (e.g. rendering an author profile page). Walks
* the configured locale fallback chain — same pattern as `getMenu` and
* `getTerm`, see PR #916. Returns the first match found, walking
* `[requestedLocale, ...fallbacks, defaultLocale]` in order.
*
* Note: this is intentionally different from credit hydration on a content
* entry (`getEntryBylines`), which is strict per locale with no fallback.
* The distinction: identity lookups answer "give me this byline", and
* falling back to another locale's display name is acceptable. Credit
* hydration answers "what should render on this entry", where falling back
* silently surfaces a stale-locale name and contradicts editorial intent.
*
* @example
* ```ts
* import { getBylineBySlug } from "emdash";
*
* const byline = await getBylineBySlug("jane-doe", { locale: "de-de" });
* if (byline) {
*   console.log(byline.displayName);
* }
* ```
*/
async function getBylineBySlug(slug, options) {
	const chain = resolveLocaleChain(options?.locale);
	return requestCached(`byline-by-slug:${slug}:${chain.length > 0 ? chain.join(",") : "*"}`, async () => {
		const repo = new BylineRepository(await getDb());
		if (chain.length === 0) return repo.findBySlug(slug);
		for (const locale of chain) {
			const row = await repo.findBySlug(slug, { locale });
			if (row) return row;
		}
		return null;
	});
}
/**
* Batch-fetch byline credits for multiple content entries.
*
* Per-entry strict-locale hydration: entries are bucketed by `entry.locale`
* and each bucket gets a single batched call to the strict-locale repo
* method. Items with no `locale` field (legacy / single-locale installs)
* share an unscoped bucket.
*
* Internal: consumed by `hydrateEntryBylines` in `query.ts` so that every
* entry returned from `getEmDashCollection` / `getEmDashEntry` already has
* `data.bylines` populated. Site code should rely on that eager hydration
* rather than calling this directly -- this function is not re-exported
* from the `emdash` package entry point.
*
* @param collection - The collection slug (e.g., "posts")
* @param entries - Entry id + authorId + locale (each entry resolves at its own locale)
* @returns Map from entry ID to array of byline credits
*/
async function getBylinesForEntries(collection, entries) {
	validateIdentifier(collection, "collection");
	const result = /* @__PURE__ */ new Map();
	for (const { id } of entries) result.set(id, []);
	if (entries.length === 0) return result;
	const repo = new BylineRepository(await getDb());
	const buckets = /* @__PURE__ */ new Map();
	for (const entry of entries) {
		const key = entry.locale ?? null;
		const bucket = buckets.get(key);
		if (bucket) bucket.push(entry);
		else buckets.set(key, [entry]);
	}
	const explicitByEntry = /* @__PURE__ */ new Map();
	const entriesNeedingAuthorCheck = [];
	const hydrationTargets = [];
	for (const [locale, bucket] of buckets) {
		const localeOpt = locale ? {
			locale,
			skipHydration: true
		} : { skipHydration: true };
		const bucketIds = bucket.map((e) => e.id);
		let bylinesMap;
		try {
			bylinesMap = await repo.getContentBylinesMany(collection, bucketIds, localeOpt);
		} catch (error) {
			if (isMissingTableError(error)) return result;
			throw error;
		}
		for (const [id, list] of bylinesMap) {
			explicitByEntry.set(id, list);
			for (const credit of list) hydrationTargets.push(credit.byline);
		}
		for (const entry of bucket) {
			if (bylinesMap.has(entry.id) && bylinesMap.get(entry.id).length > 0) continue;
			if (entry.authorId) entriesNeedingAuthorCheck.push(entry);
		}
	}
	const fallbackByEntry = /* @__PURE__ */ new Map();
	if (entriesNeedingAuthorCheck.length > 0) {
		const authorBuckets = /* @__PURE__ */ new Map();
		for (const entry of entriesNeedingAuthorCheck) {
			if (entry.primaryBylineId) continue;
			const key = entry.locale ?? null;
			const bucket = authorBuckets.get(key);
			if (bucket) bucket.push(entry);
			else authorBuckets.set(key, [entry]);
		}
		for (const [locale, bucket] of authorBuckets) {
			const localeOpt = locale ? {
				locale,
				skipHydration: true
			} : { skipHydration: true };
			const authorIds = bucket.map((e) => e.authorId).filter((id) => id !== null);
			const uniqueAuthorIds = [...new Set(authorIds)];
			if (uniqueAuthorIds.length === 0) continue;
			const authorBylineMap = await repo.findByUserIds(uniqueAuthorIds, localeOpt);
			for (const entry of bucket) {
				if (!entry.authorId) continue;
				const f = authorBylineMap.get(entry.authorId);
				if (f) {
					fallbackByEntry.set(entry.id, f);
					hydrationTargets.push(f);
				}
			}
		}
	}
	if (hydrationTargets.length > 0) await repo.hydrateBylineCustomFields(hydrationTargets);
	for (const { id } of entries) {
		const explicit = explicitByEntry.get(id);
		if (explicit && explicit.length > 0) {
			result.set(id, explicit.map((c) => ({
				...c,
				source: "explicit"
			})));
			continue;
		}
		const fallback = fallbackByEntry.get(id);
		if (fallback) result.set(id, [{
			byline: fallback,
			sortOrder: 0,
			roleLabel: null,
			source: "inferred"
		}]);
	}
	return result;
}
/**
* Get content entries credited to a byline, in any credit position.
*
* Unlike filtering on the content table's `primary_byline_id` column (which
* only finds entries where the byline is the first/primary credit), this
* matches every explicit credit recorded in `_emdash_content_bylines`, so
* co-authored entries where the byline is a secondary credit are included.
*
* `byline` is matched against the byline's `translation_group` (the value
* stored on credits since migration 040), so a single credit spans every
* locale variant of the byline. Pass `byline.translationGroup ?? byline.id`
* from `getByline` / `getBylineBySlug`. An array matches any of the given
* bylines (OR).
*
* The result respects the active locale, status, ordering, and eager
* hydration of `getEmDashCollection`.
*
* @example
* ```ts
* import { getBylineBySlug, getEntriesByByline } from "emdash";
*
* const byline = await getBylineBySlug("jane-doe");
* if (byline) {
*   const posts = await getEntriesByByline("posts", byline.translationGroup ?? byline.id, {
*     orderBy: { published_at: "desc" },
*   });
* }
* ```
*
* @param collection - The collection slug (e.g. "posts")
* @param byline - A byline translation group, or an array of them (OR)
* @param options - Optional locale, ordering, status, and limit
*/
async function getEntriesByByline(collection, byline, options = {}) {
	const { getEmDashCollection } = await import("./query-ByGq6ver.mjs").then((n) => n.o);
	const queryOptions = { where: { byline } };
	if (options.locale !== void 0) queryOptions.locale = options.locale;
	if (options.orderBy !== void 0) queryOptions.orderBy = options.orderBy;
	if (options.status !== void 0) queryOptions.status = options.status;
	if (options.limit !== void 0) queryOptions.limit = options.limit;
	const { entries } = await getEmDashCollection(collection, queryOptions);
	return entries;
}

//#endregion
export { invalidateBylineCache as a, getEntriesByByline as i, getByline as n, getBylineBySlug as r, bylines_exports as t };
//# sourceMappingURL=bylines-Woq87129.mjs.map