import type { RecipeSourceAdapter } from "./recipe-source-adapter.js"; /** * In-memory registry of every {@link RecipeSourceAdapter} (recipe-source-adapter.ts) * this process knows about, keyed by `adapter.key`. Deliberately not * DB-backed — an adapter *is* code (a website's fetch/parse logic can't * live in a database row) — but the `Source` table (schema.prisma) is kept * in sync with it (see `syncRecipeSources`, recipe-source-sync.ts) so a * saved `Recipe.sourceId` has a row to point at. Actually saving an * imported recipe (setting `Recipe.sourceId`/`externalId`) is still future * work for whichever module ends up driving the import pipeline — this * registry only answers "which sources can we import from right now". * * No adapter is registered here yet — this file only provides the * mechanism; `registerRecipeSource` is meant to be called once per adapter * module, at whatever point a concrete source is added. */ const adapters = new Map(); /** * Registers `adapter` under its own `key`. Throws if that key is already * taken — two adapters silently overwriting each other would be a bug (a * caller reaching for "marmiton" should never get a different adapter than * the one it registered), not a case to swallow. */ export function registerRecipeSource(adapter: RecipeSourceAdapter): void { if (adapters.has(adapter.key)) { throw new Error(`Recipe source "${adapter.key}" is already registered`); } // `TRawDetail` only matters within one adapter's own list/fetchDetail/parse // trio — once stored, callers look adapters up by key and drive the same // three methods generically, so the registry itself doesn't need to know // each adapter's raw type. This cast is the standard way to store a // heterogeneous collection of otherwise-identically-shaped generics. adapters.set(adapter.key, adapter as RecipeSourceAdapter); } /** The adapter registered under `key`, or `undefined` if none is. */ export function getRecipeSource(key: string): RecipeSourceAdapter | undefined { return adapters.get(key); } /** Every registered adapter — e.g. to offer a source picker. */ export function listRecipeSources(): RecipeSourceAdapter[] { return [...adapters.values()]; } /** * Empties the registry. Not meant for application code — `apps/api/src` * never calls this — only for test isolation, the same role * `test-support/reset-db.ts` plays for the database: without it, adapters * registered by one test file would leak into the next. */ export function clearRecipeSources(): void { adapters.clear(); }