You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Companion to the @run402/sdk@2.3.0 / run402@2.3.0 / run402-mcp@2.3.0 release.
Adds coverage of the new SDK-side convenience getters and the responsive
<picture> emitter, with the foolproof-for-non-images contract explicitly
called out. Drops the now-stale @run402/functions@2.3.0+ marker since that
package ships on its own cadence from the private repo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`immutable: true` is the default since v1.45 — the SDK computes the SHA-256 client-side and the gateway returns a content-addressed URL paired with SRI. The resulting URL never needs cache invalidation, never breaks on re-deploys, never needs `cdn wait-fresh` follow-up. The SDK and CLI always compute and send the object SHA-256 because upload sessions require it; pass `{ immutable: false }` only when you need mutable URL/cache semantics. In that case the tag emitters throw because there's no immutable URL/SRI to bind. The tag emitters also bake in modern best-practice attributes — `defer` on `<script>`, `loading="lazy"` + `decoding="async"` on `<img>` — so the agent doesn't have to remember.
@@ -877,13 +880,17 @@ Other AssetRef fields for advanced use:
- `blurhash` — ~30-byte LQIP placeholder; decode client-side with the `blurhash` npm package to render a placeholder before the real image is ready (eliminates CLS).
- `width_px`, `height_px` — display-oriented dimensions (post-EXIF rotate). `imgTag` emits these as `<img width height>` attributes when present (eliminates CLS).
885
+
- `blurhash` — ~30-byte LQIP placeholder; decode client-side with the `blurhash` npm package to render a placeholder before the real image is ready.
883
886
- `variant_spec_version` — pins URL identity to the encoder generation. Bumping (gateway-side) produces new URLs without invalidating older ones.
884
-
- `display_url` / `display_immutable_url` — browser-displayable URL. For jpeg/png/webp/avif sources this equals `cdn_url`. For **HEIC/HEIF** sources this points at a JPEG `display_jpeg` variant so `<img src>` renders correctly without HEIC-specific app code. HEIC source bytes are preserved verbatim in CAS (uploaded SHA == stored SHA).
887
+
- `display_url` / `display_immutable_url` — browser-displayable URL. For jpeg/png/webp/avif sources this equals `cdn_url`. For **HEIC/HEIF** sources this points at a JPEG `display_jpeg` variant so `<img src>` renders correctly without HEIC-specific app code. HEIC source bytes are preserved verbatim in CAS (uploaded SHA == stored SHA). The `imgTag` / `imgTagWithSrcSet` helpers default `<img src>` to `display_url` so HEIC just works.
885
888
- `variants.thumb` / `variants.medium` / `variants.large` — three WebP variants (320w / 800w / 1920w), each with `url`, `cdn_url`, `width_px`, `height_px`, `format: "webp"`, `sha256`. Use `variants.thumb.cdn_url` in MediaPicker-style admin grids to avoid downloading full-res originals.
886
889
- `variants.display_jpeg` — only present for HEIC/HEIF sources. Full-res JPEG, quality 90, sRGB-converted.
890
+
- `thumbUrl` (SDK convenience, v2.3+) — `variants.thumb.cdn_url ?? displayUrl` for image refs; **`undefined` for non-image AssetRefs**. Single field for grid thumbnails — TypeScript narrows so `<img src={pdfRef.thumbUrl}>` is a compile error rather than a broken thumbnail at runtime.
891
+
- `displayUrl` (SDK convenience, v2.3+) — `display_url ?? cdn_url` for image refs; **`undefined` for non-images**. Use for hero / single-image render paths.
892
+
- `imgTagWithSrcSet(opts)` (SDK helper, v2.3+) — emits `<picture>` with WebP-only `<source>` (three sizes) and `display_url` as the `<img>` fallback. Throws at call time on missing `opts.sizes` (browsers over-fetch the largest candidate without it) OR missing `variants` (use `imgTag()` instead — no silent fallback). AVIF deferred from v1 (`<picture>` type-precedence footgun: AVIF must land at all three sizes simultaneously or via a separate `imgTagHero()` helper).
893
+
- Both write paths produce identical `AssetRef` shapes: `r.assets.put(...)` and `r.project(id).apply({ assets: { put: [...] } })`. Pickers can use either entry point.
887
894
- Encoder errors surface as HTTP 422 `IMAGE_DECODE_FAILED`, 413 `IMAGE_INPUT_TOO_LARGE` (>40 MP or >12000 px any axis), 504 `IMAGE_ENCODE_TIMEOUT`, 429 `TOO_MANY_ENCODES_QUEUED` (encoder semaphore full — retry after 2s).
888
895
889
896
**Agent loop pattern (mutable URL only):** if you must use a stable mutable URL across re-uploads, `run402 cdn wait-fresh <mutable-url> --sha <new-sha>` blocks until the CDN serves the new SHA. **Don't call wait-fresh on immutable URLs** — they're correct from the moment of upload.
0 commit comments