v2.3.0 — Image variants on AssetRef
Surfaces the v1.49 gateway image-variant pipeline in @run402/sdk, run402 (CLI), and run402-mcp. Additive, non-breaking — old clients silently ignore the new fields. Lockstep release across the three packages.
What's new for developers
Image uploads now return rich metadata. Upload a JPEG/PNG/WebP/HEIC/HEIF via r.assets.put(...) or r.project(id).apply({ assets: { put: [...] } }) and the returned AssetRef carries:
width_px,height_px— display-oriented dimensions (post-EXIF rotate)blurhash— LQIP placeholder, decode client-sidevariants.thumb(320w WebP),variants.medium(800w WebP),variants.large(1920w WebP)display_url— browser-renderable URL; equalscdn_urlfor jpeg/png/webp, points to a generated JPEG transcode for HEIC/HEIFvariants.display_jpeg— full-resolution JPEG transcode (HEIC/HEIF sources only)
Both write paths produce structurally identical AssetRef shapes.
New typed convenience getters — foolproof for non-images.
ref.thumbUrl— single field for grid thumbnails.undefinedfor non-image AssetRefs, so TypeScript narrows and a picker that does `` is a compile error rather than a broken thumbnail at runtime.
ref.displayUrl— single field for browser-renderable URL.undefinedfor non-images. HEIC sources transparently get the JPEG transcode.
New ref.imgTagWithSrcSet(opts) helper — emits a <picture> with WebP-only sources at 320w / 800w / 1920w and display_url as the <img> fallback. Throws at call time on missing opts.sizes (browsers over-fetch the largest candidate without it) AND on missing variants (use imgTag() instead). No silent fallback.
ref.imgTag(alt?) now HEIC-aware. Default <img src> is display_url ?? cdn_url, and width/height attributes are opportunistically emitted when known (eliminates CLS for image grids). Never throws on absence.
MCP assets_put tool output surfaces Dimensions, Blurhash, Display URL (HEIC only), and a Variants: line listing kind + size + format. CLI is JSON-only by design — new fields flow through JSON.stringify automatically.
Out of scope (deliberate)
@run402/functionstypes — that package lives in the private gateway monorepo and ships on its own cadence via/publish-functions. The runtime returns the new fields regardless.- AVIF generation — deferred;
<picture>type-precedence footgun means AVIF must land at all three sizes simultaneously or via a dedicatedimgTagHero()helper. - On-demand
?w=N&fmt=webpresize and project-configurable variant sizes — separate future changes.
Links
- @run402/sdk@2.3.0 on npm
- run402-mcp@2.3.0 on npm
- run402@2.3.0 on npm
- Parent gateway change: asset-image-variants in run402-private
- Tracking issue: run402#392