// ---------------------------------------------------------------------------
// 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
;
}