Skip to content

Commit eb45697

Browse files
MajorTalclaude
andcommitted
docs(llms-cli): add SDK v2.3 image-variant helpers (thumbUrl, displayUrl, imgTagWithSrcSet)
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>
1 parent 2836633 commit eb45697

1 file changed

Lines changed: 12 additions & 5 deletions

File tree

cli/llms-cli.txt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,10 @@ run402 cdn wait-fresh https://app.run402.com/_blob/avatar.png --sha ba78... --ti
862862
const asset = await client.assets.put(projectId, key, { bytes }); // v1.45 defaults to immutable: true
863863
html += asset.scriptTag(); // <script src=... defer integrity=... crossorigin></script>
864864
html += asset.linkTag(); // <link rel="stylesheet" href=... integrity=... crossorigin>
865-
html += asset.imgTag("Company logo"); // <img src=... alt="Company logo" loading="lazy" decoding="async">
865+
html += asset.imgTag("Company logo"); // <img src=... alt="Company logo" width=... height=... loading="lazy" decoding="async">
866+
html += asset.imgTagWithSrcSet({ alt: "Hero", sizes: "(max-width: 800px) 100vw, 1920px" });
867+
// → <picture><source type="image/webp" srcset="<thumb> 320w, <medium> 800w, <large> 1920w" sizes="…">
868+
// <img src="<display_url>" alt="Hero" width="…" height="…" loading="lazy" decoding="async"></picture>
866869
```
867870

868871
`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:
877880
- `cacheKind` — `"immutable" | "mutable" | "private"`.
878881
- `cdn.{version,invalidationId,invalidationStatus,ready,hint}` — CloudFront invalidation envelope; `cdn.ready === true` for immutable uploads.
879882

880-
Image-variant fields (v1.49+, `@run402/functions@2.3.0+`, populated for image MIMEs ≥ 320×320):
881-
- `width_px`, `height_px` — display-oriented dimensions (post-EXIF rotate).
882-
- `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).
883+
Image-variant fields (v1.49+ gateway, `@run402/sdk@2.3.0+`, populated for image MIMEs ≥ 320×320):
884+
- `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.
883886
- `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.
885888
- `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.
886889
- `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.
887894
- 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).
888895

889896
**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

Comments
 (0)