// --------------------------------------------------------------------------- // Preset icon — a preset's `icon` is usually a plain image URL. A preset whose // icon can only come from the local server (e.g. a Codex plugin's own icon, // read off this machine at runtime) uses the `executor:` scheme instead: the // path after the scheme is fetched from the executor API with the server auth // header and must answer `{ icon: string | null }` (a data URI). The // indirection exists because local auth is deliberately bearer-header-only — // an cannot authenticate itself. // --------------------------------------------------------------------------- import { useEffect, useState } from "react"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import { getExecutorApiBaseUrl, getExecutorServerAuthorizationHeader, } from "../api/server-connection"; export const EXECUTOR_ICON_SCHEME = "executor:"; const IconResponse = Schema.Struct({ icon: Schema.NullOr(Schema.String) }); const decodeIconResponse = Schema.decodeUnknownOption(IconResponse); const resolved = new Map>(); /** Resolve an `executor:`-scheme icon path to its data URI (or null). Shared * by every surface that renders preset icons, including IntegrationFavicon's * cascade. Results are memoized per path for the session; any failure is * "no icon", never an error. */ export const resolveExecutorIcon = (path: string): Promise => { const cached = resolved.get(path); if (cached) return cached; const authorization = getExecutorServerAuthorizationHeader(); const request = Effect.runPromise( Effect.tryPromise(async () => { const response = await fetch(`${getExecutorApiBaseUrl()}${path}`, { headers: authorization === null ? {} : { authorization }, }); if (!response.ok) return null; const body: unknown = await response.json(); return Option.match(decodeIconResponse(body), { onNone: () => null, onSome: ({ icon }) => icon, }); }).pipe(Effect.orElseSucceed(() => null)), ); resolved.set(path, request); return request; }; /** Renders a preset icon, resolving `executor:` scheme icons through the * authenticated API. * * `fallbackSrc` is a plain image URL to use when the machine-local icon is * unavailable — a Codex plugin card still shows its provider's mark on a * machine where Codex is not installed, which is exactly when the card is * most in need of explaining itself. `fallback` is the last resort, for when * there is no image of any kind. */ export function PresetIcon(props: { readonly icon?: string; readonly fallbackSrc?: string; readonly className?: string; readonly fallback?: React.ReactNode; }) { const isExecutorIcon = props.icon?.startsWith(EXECUTOR_ICON_SCHEME) ?? false; const [fetched, setFetched] = useState(null); useEffect(() => { if (!isExecutorIcon || props.icon === undefined) return; let live = true; void resolveExecutorIcon(props.icon.slice(EXECUTOR_ICON_SCHEME.length)).then((icon) => { if (live) setFetched(icon); }); return () => { live = false; }; }, [isExecutorIcon, props.icon]); const src = (isExecutorIcon ? fetched : (props.icon ?? null)) ?? props.fallbackSrc ?? null; if (src === null) return <>{props.fallback ?? null}; return ; }