import satori, { init as initSatori } from "satori/standalone";
import { initWasm, Resvg } from "@resvg/resvg-wasm";
import type { ReactNode } from "react";
import { OG_HEIGHT, OG_WIDTH } from "~/lib/og";
/** Wasm modules and font bytes; the Worker passes bundled modules, tests and scripts read the same files from disk. */
export type OgRuntime = {
yoga: WebAssembly.Module;
resvg: WebAssembly.Module;
fonts: { regular: ArrayBuffer; semibold: ArrayBuffer };
};
let satoriReady: Promise<void> | null = null;
let resvgReady: Promise<void> | null = null;
function alreadyInitialized(error: unknown): boolean {
return error instanceof Error && error.message.startsWith("Already initialized");
}
/** Each wasm instance lives for the isolate and is initialized once; a failed init is retried on the next render. */
function ensureReady(runtime: OgRuntime): Promise<[void, void]> {
satoriReady ??= initSatori(runtime.yoga).catch((error: unknown) => {
satoriReady = null;
throw error;
});
resvgReady ??= initWasm(runtime.resvg).catch((error: unknown) => {
// A reloaded module (dev HMR) loses this flag while resvg keeps its instance.
if (alreadyInitialized(error)) return;
resvgReady = null;
throw error;
});
return Promise.all([satoriReady, resvgReady]);
}
export async function renderPng(element: ReactNode, runtime: OgRuntime): Promise<Uint8Array> {
await ensureReady(runtime);
const svg = await satori(element, {
width: OG_WIDTH,
height: OG_HEIGHT,
fonts: [