import { type MediaUploadOp, type PushPolicy, type RefValue } from "../ir/operations.js"; import { type CompileContext } from "./shared.js"; /** * True when an image path/URL is a fully-qualified external URL rather * than a media-library path. */ export declare const isExternalMediaUrl: (path: string) => boolean; /** * Accumulator for the `MediaUpload` ops a compile emits alongside field * values. Callers own ordering: push `mediaOps` into the operation list * BEFORE the CreateItem/SetField ops whose `media-xml-ref` values * reference them, so the executor captures each media itemId first. */ export interface ImageMediaSink { policy: PushPolicy; mediaOps: MediaUploadOp[]; /** * Media-library folder the uploads land under — from * `CompileContext.mediaLibraryRoot`. Unset → the flat * `/sitecore/media library/RecipeImages/` fallback. */ mediaLibraryRoot?: string; /** * Pre-resolved folder from the recipe's `mediaLocation` declaration * (see `resolveMediaLocationFolder`). When set it wins over * `mediaLibraryRoot` and skips the `/` nesting — the * author owns the layout. A per-image `mediaLibraryFolder` still * overrides this. */ locationFolder?: string; /** * Brand image-defaults map (role → external URL) from * `CompileContext.imageDefaults` (`--image-defaults `). * An image value that carries a `role` present in this map * materialises the mapped URL instead of its recipe-authored one — * the substitution seam that keeps recipes brand-agnostic while an * installer supplies brand-appropriate imagery. */ imageDefaults?: Readonly>; } /** * Resolve a recipe's `mediaLocation` declaration to the absolute * media-library folder its uploads land under — the media twin of the * datasource-locations model. Returns `undefined` when no location is * declared (callers fall back to the default `//` * nesting). * * - `site` → `/` * - `page` → `//` — * only valid where a host page exists; callers that have no page * (content items, template SV defaults) omit `pageRelativePath` * and the compiler rejects the scope with INPUT_INVALID. */ export declare const resolveMediaLocationFolder: (location: { scope: "page" | "site"; subfolder?: string; } | undefined, opts: { context: CompileContext; site: string; recipeHandle: string; /** The page item's path relative to `pagesRoot` — page recipes only. */ pageRelativePath?: string; }) => string | undefined; /** * Materialise an external image URL as a media-library item: emit (or * dedupe onto) a `MediaUpload` op in the sink and return the * `media-xml-ref` value the consuming field stores. At apply time the * executor uploads the bytes, captures the server-assigned media * itemId, and resolves the ref to `` — the * form Pages' canvas, the Layout Service, and Edge all render. * * The refKey is deterministic per (site, recipe, field, URL), so the * same avatar repeated across languages/versions uploads once, while a * story that swaps the image per version gets one media item per URL. * The destination basename embeds a refKey fragment so two different * URLs on the same field can't collide on one media path (the * executor's idempotency lookup would otherwise capture the first * upload's item for both). * * Destination folder resolution, most-specific first: * 1. `folder` (the image value's own `mediaLibraryFolder`) — used * as-is; only the generated leaf is appended. * 2. `sink.locationFolder` (the recipe's `mediaLocation` declaration, * page- or site-scoped) — used as-is, no `/` nesting. * 3. `sink.mediaLibraryRoot` (from `CompileContext.mediaLibraryRoot`, * i.e. env-profile `recipeRoots.mediaLibrary` / `--media-library-root`) * — uploads nest under `//`. * 4. Fallback: `/sitecore/media library/RecipeImages///`. * * **Role-substituted images are SITE-LEVEL, not per-recipe.** When an * image-defaults override fires, the media item is a brand default the * whole site shares — so its refKey is scoped to (site, role, URL) * instead of (site, recipe, field, URL), and it lands under * `/Defaults/-`. Every component/recipe that maps the * same role resolves the SAME refKey: within one push the first * MediaUpload captures the itemId and later duplicates skip; across * pushes the executor's path-based idempotency lookup reuses the * existing item. One brand image per role per site, uploaded once. */ export declare const externalImageMediaRef: (opts: { site: string; recipeHandle: string; fieldName: string; url: string; alt?: string; /** * Semantic image role — when set AND `substituteRole` is true AND * `sink.imageDefaults` maps it, the mapped URL replaces `url` before * materialisation (brand substitution). The refKey derives from the * EFFECTIVE URL, so two brands' maps yield distinct media items on * the same field. */ role?: string; /** * Opt-in for image-defaults substitution. Set ONLY by the template * Standard-Values path — SV defaults are the component's stock * imagery, which is exactly what the brand map exists to replace. * AUTHORED content values (page/content-item images, exported story * imagery) must never be overridden by a role default: the author's * value always wins over the standard value. */ substituteRole?: boolean; /** Per-value destination folder override (`image.mediaLibraryFolder`). */ folder?: string; sink: ImageMediaSink; }) => RefValue;