/** * Post-fetch href fallback for an inline chat card whose `ChatRef` carried no * `externalUrl`. * * ## Why a fetch-mode card can arrive without a URL * * The two chat transports deliver entity references differently: * * - **SSE / guide transport** — the server ships a `refs` metadata frame, so * each `[card://type:id]` marker expands into a FULL `ChatRef` * (`title` / `url` / `targetPlatform` / `sourceRepo`). `resolveSourceRowCTA` * then routes that `externalUrl` through the host's `composeContentUrl` * seam and the card is clickable. * - **Mingo / NATS transport** (`messageData: [{ type: 'TEXT', text }]`) * — the body carries bare `[card://type:id]` markers and NOTHING else. * `chat-message-enhanced.tsx` synthesizes a minimal `{ type, id, title: id, * url: null }` ref so fetch-mode cards can still self-fetch their row, but * `resolveSourceRowCTA` has no `externalUrl`, no `path` and no * `targetPlatform` to work with → `href: null` → the card renders with its * real title and description but goes nowhere when clicked. * * This resolver closes that gap WITHOUT a second URL vocabulary: it calls the * exact same `composeContentUrl` seam the page cards (`resolveContentHref`) and * the SSE cards (`resolveSourceRowCTA`) use, so one host config — * `hostedTypes` / `suffixes` / `overrides` — governs all three. * * `identifier` stays the marker's primary key (that is what `overrides` such as * roadmap's `?search=` deep-link on); the row's `slug` rides the * separate `slug` hint for hosted types whose detail route is slug-based. * * Pure — no React, no DOM. The caller owns `safeHref` validation. */ import type { ComposeContentUrl, ComposedContentUrl } from '../../../utils/content-href'; export interface FetchedCardHrefInput { /** Canonical `documentType` for the seam (registry `contentRefType`). */ contentRefType: string; /** The marker's primary key — `ChatRef.id`, NOT the fetched row's id. */ id: string; /** The row the card fetched. Shape is per-type and opaque here; only * `slug` and `platforms` are read, both defensively. */ item: unknown; /** Host seam. Absent (unwired runtime) → no fallback, same as today. */ composeContentUrl?: ComposeContentUrl; } /** * Human title of a fetched row — `title`, else `name`, else null. * * A Mingo synthetic ref carries `title: ` because that is all * the transport shipped. Everything downstream that prints or sends the title * (the "Ask Mingo" prompt, host renderers falling back to `ref.title`) would * otherwise say `86ad3qvv5`. Once the row loads, this is the real title. */ export declare function readFetchedCardTitle(item: unknown): string | null; /** * Resolve `{href, targetPlatform}` for a freshly fetched card row, or `null` * when the host wired no seam (the caller then keeps the card unlinked, which * is the pre-existing behavior). */ /** * Where a fetch-mode card's destination came from. The loader needs the source, * not just the string: only the `item` branch must leave the ref's own * `targetPlatform` untouched. */ export type FetchedCardHrefChoice = { source: 'hostOverride'; href: string; targetPlatform: string | null; } | { source: 'item'; href: string; targetPlatform?: undefined; } | { source: 'composed'; href: string; targetPlatform: string | null; }; /** * Decide a fetched card's destination between the two producers that can claim * it. Pure, so the precedence is testable on its own — it used to live as * inline ternaries in `ChatCardLoader`. * * 1. an EXPLICIT host override — the host said where this type lives in its * own app, which beats everything; * 2. the fetched row's own url (`registry.fallbackHref`) — minted by the * content host for ITS surface, authoritative in the absence of (1); * 3. the composer's synthesized href, unless the registry opted out * (`noComposedHref`) because the synthesis would be a 404. * * (2) beating (3) is why `noComposedHref` exists; (1) beating (2) is what keeps * a re-homed type (an embedder serving hub tickets under `/help-center/tickets`) * from following the content host's path into an unrelated route of its own. */ export declare function pickFetchedCardHref({ composed, itemHref, allowComposed, }: { /** Result of {@link resolveFetchedCardHref}, or null when unresolvable. */ composed: ComposedContentUrl | null; /** `registry.fallbackHref(item)` — the fetched row's own destination. */ itemHref: string | null; /** False for registry entries flagged `noComposedHref`. */ allowComposed: boolean; }): FetchedCardHrefChoice | null; export declare function resolveFetchedCardHref({ contentRefType, id, item, composeContentUrl, }: FetchedCardHrefInput): ComposedContentUrl | null; //# sourceMappingURL=resolve-fetched-card-href.d.ts.map