@nitida/sdk 0.36.2 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -608,7 +608,7 @@ this table from the source, so it can't have the wrong one.
608
608
  | `sm` | `s` | 640 | mobile thumbs, list cards |
609
609
  | `md` | `m` | 1280 | desktop cards, modal previews |
610
610
  | `lg` | `l` | 1920 (≈2K) | hero, full-bleed |
611
- | `xl` | `x` | 3840 (4K) | print, 4K screens |
611
+ | `xl` | `x` | 3840 (4K) | print, 4K screens · a clean WebP base ≤ 3840 is reused as-is |
612
612
 
613
613
  **Defaults — what actually runs:**
614
614
 
@@ -644,6 +644,16 @@ the full responsive ladder ≈ 4× source bytes.
644
644
  (3840) yields a 1080×720 `xl` variant, not a blurry 3840-wide stretch.
645
645
  The preset is a **ceiling**, not a target.
646
646
 
647
+ **`xl` reuses a ≤ 4K base byte-for-byte.** 4K is the cap for listing
648
+ photos. When the uploaded base is a clean WebP no larger than 3840 px
649
+ (single frame, no EXIF orientation, no EXIF/XMP), the server stores it
650
+ as `xl` unchanged: same sha256, no second lossy pass. Anything else (a
651
+ larger base, JPEG/PNG/HEIC, animated or EXIF-bearing WebP) is re-encoded
652
+ to WebP q82 as before. The default `compressImage` output (3840 px WebP)
653
+ qualifies. URLs, keys and response shapes do not change; `xl` is still
654
+ its own object, the same size as the base. Already-stored assets keep
655
+ their existing `xl`.
656
+
647
657
  ### Non-image / passthrough
648
658
 
649
659
  | Preset | Code | Purpose |
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ResolveSlotOptions, SlotResolution, SlotDTO, VariantPreset, AssetDTO, AssetVariant, RequestablePreset, TransformOptions, SignedTransformOptions, SignTransformOptions, TransformWidth } from '@nitida/asset-client';
2
- export { AssetDTO, AssetPalette, AssetVariant, HlsRung, MAX_SIGNED_TRANSFORM_TTL_SECONDS, MAX_SIGNED_URL_TTL_SECONDS, MIN_SIGNED_TRANSFORM_TTL_SECONDS, PRESET_EXT, PRESET_LONG, PRESET_MAX_DIM, PRESET_SHORT, PaletteSwatch, PrivateTransformOptions, REQUESTABLE_PRESETS, RequestablePreset, ResolveSlotOptions, SignAccessOptions, SignTransformOptions, SignedTransformOptions, SlotDTO, SlotResolution, TRANSFORM_WIDTHS, TransformEffect, TransformFit, TransformFormat, TransformGravity, TransformOptions, TransformWidth, VariantEntryPreset, VariantPreset, VisibilityHint, accessMessage, assertPublic, assertSha, bestTextContrast, computeVariantDimensions, configureSlotResolver, contrastRatio, deriveAccessKey, deriveTransformKid, extractAssetSha, getAmbientGradient, getAssetDimensions, getAssetSrcSet, getAssetUrl, getByteBudgetTransformUrl, getCdnBase, getHlsLadder, getHlsStreamingUrl, getPaletteBlurBackground, getPaletteCssVars, getPrivateAssetUrl, getPrivateTransformUrl, getSignedTransformUrl, getTenantId, getTextColorForBackground, getTransformSrcSet, getTransformUrl, getVideoTransformUrl, hasPreset, hasSizeLadder, hlsLadderAlignment, invalidateSlotCache, isRequestablePreset, iteratePaletteSwatches, pickAmbientBackground, relativeLuminance, resolveSlot, resolveSlots, serializeTransform, setCdnBase, setTenantId, signAccessUrl, signTransformUrl, toRequestablePresets, transformMessage } from '@nitida/asset-client';
1
+ import { ResolveSlotOptions, SlotResolution, SlotDTO, VariantPreset, AssetDTO, AssetVariant, RequestablePreset, ImageRole, TransformOptions, SignedTransformOptions, SignTransformOptions, TransformWidth } from '@nitida/asset-client';
2
+ export { AssetDTO, AssetPalette, AssetVariant, HlsRung, IMAGE_LADDER, IMAGE_ROLES, IMAGE_ROLE_LADDERS, ImageRole, MAX_SIGNED_TRANSFORM_TTL_SECONDS, MAX_SIGNED_URL_TTL_SECONDS, MIN_SIGNED_TRANSFORM_TTL_SECONDS, PRESET_EXT, PRESET_LONG, PRESET_MAX_DIM, PRESET_SHORT, PaletteSwatch, PrivateTransformOptions, REQUESTABLE_PRESETS, RequestablePreset, ResolveSlotOptions, SignAccessOptions, SignTransformOptions, SignedTransformOptions, SlotDTO, SlotResolution, TRANSFORM_WIDTHS, TransformEffect, TransformFit, TransformFormat, TransformGravity, TransformOptions, TransformWidth, VariantEntryPreset, VariantPreset, VisibilityHint, accessMessage, assertPublic, assertSha, bestTextContrast, computeVariantDimensions, configureSlotResolver, contrastRatio, deriveAccessKey, deriveTransformKid, extractAssetSha, getAmbientGradient, getAssetDimensions, getAssetSrcSet, getAssetUrl, getByteBudgetTransformUrl, getCdnBase, getHlsLadder, getHlsStreamingUrl, getPaletteBlurBackground, getPaletteCssVars, getPrivateAssetUrl, getPrivateTransformUrl, getRoleLadder, getRolesLadder, getSignedTransformUrl, getTenantId, getTextColorForBackground, getTransformSrcSet, getTransformUrl, getVideoTransformUrl, hasPreset, hasSizeLadder, hlsLadderAlignment, invalidateSlotCache, isImageRole, isRequestablePreset, iteratePaletteSwatches, pickAmbientBackground, relativeLuminance, resolveSlot, resolveSlots, serializeTransform, setCdnBase, setTenantId, signAccessUrl, signTransformUrl, toRequestablePresets, transformMessage } from '@nitida/asset-client';
3
3
 
4
4
  /**
5
5
  * Which audio uploads already play everywhere — the single source of truth for
@@ -300,6 +300,14 @@ type PresignUploadUrlOptions = {
300
300
  clientOriginalBytes?: number;
301
301
  /** VIDEO-only delivery knobs forwarded into `/assets/process`. See {@link UploadVideoOptions}. */
302
302
  video?: UploadVideoOptions;
303
+ /**
304
+ * Image roles whose transform ladder (`IMAGE_ROLE_LADDERS`) the platform warms
305
+ * at the CDN edge once the asset is ready, so the first visitor does not pay
306
+ * a cold encode. Omit to warm nothing. Ignored for non-images and when the
307
+ * bytes were already stored (a deduped upload runs no processing; use the
308
+ * backfill for those).
309
+ */
310
+ warm?: ImageRole[];
303
311
  };
304
312
  /** Input shape accepted by `aq.assets.composeMarketing(...)`. */
305
313
  type ComposeMarketingSegment = {
@@ -604,6 +612,14 @@ type UploadOptions = {
604
612
  * any audio original — and asking for either is a 400.
605
613
  */
606
614
  presets?: RequestablePreset[];
615
+ /**
616
+ * Image roles whose transform ladder (`IMAGE_ROLE_LADDERS`) the platform warms
617
+ * at the CDN edge once the asset is ready, so the first visitor does not pay
618
+ * a cold encode. Omit to warm nothing. Ignored for non-images and when the
619
+ * bytes were already stored (a deduped upload runs no processing; use the
620
+ * backfill for those).
621
+ */
622
+ warm?: ImageRole[];
607
623
  /**
608
624
  * Max time to wait for the asset to transition to `ready` (or `failed`)
609
625
  * after dispatch. Default `5 * 60_000` (5 min). Bump higher for large
package/dist/index.js CHANGED
@@ -75,6 +75,12 @@ import {
75
75
  signAccessUrl,
76
76
  signTransformUrl,
77
77
  TRANSFORM_WIDTHS,
78
+ getRoleLadder,
79
+ getRolesLadder,
80
+ IMAGE_LADDER,
81
+ IMAGE_ROLE_LADDERS,
82
+ IMAGE_ROLES,
83
+ isImageRole,
78
84
  toRequestablePresets as toRequestablePresets2,
79
85
  transformMessage
80
86
  } from "@nitida/asset-client";
@@ -395,6 +401,7 @@ var AssetsApi = class {
395
401
  if (opts.clientOriginalBytes != null)
396
402
  body.clientOriginalBytes = opts.clientOriginalBytes;
397
403
  if (opts.video != null) body.video = opts.video;
404
+ if (opts.warm && opts.warm.length > 0) body.warm = opts.warm;
398
405
  const r = await fetch(endpointHref(this.opts, "/assets/upload-url"), {
399
406
  method: "POST",
400
407
  headers: { ...this.headers(), "Content-Type": "application/json" },
@@ -821,7 +828,8 @@ var NitidaClient = class {
821
828
  fileName,
822
829
  presets: opts.presets && opts.presets.length > 0 ? opts.presets : DEFAULT_UPLOAD_PRESETS,
823
830
  ...clientOriginalBytes != null && { clientOriginalBytes },
824
- ...opts.video != null && { video: opts.video }
831
+ ...opts.video != null && { video: opts.video },
832
+ ...opts.warm && opts.warm.length > 0 && { warm: opts.warm }
825
833
  });
826
834
  if (presign.deduped) {
827
835
  const short = sha.slice(0, 16);
@@ -972,6 +980,9 @@ var NitidaClient = class {
972
980
  }
973
981
  };
974
982
  export {
983
+ IMAGE_LADDER,
984
+ IMAGE_ROLES,
985
+ IMAGE_ROLE_LADDERS,
975
986
  MAX_SIGNED_TRANSFORM_TTL_SECONDS,
976
987
  MAX_SIGNED_URL_TTL_SECONDS,
977
988
  MIN_SIGNED_TRANSFORM_TTL_SECONDS,
@@ -1004,6 +1015,8 @@ export {
1004
1015
  getPaletteCssVars,
1005
1016
  getPrivateAssetUrl,
1006
1017
  getPrivateTransformUrl,
1018
+ getRoleLadder,
1019
+ getRolesLadder,
1007
1020
  getSignedTransformUrl2 as getSignedTransformUrl,
1008
1021
  getTenantId,
1009
1022
  getTextColorForBackground,
@@ -1014,6 +1027,7 @@ export {
1014
1027
  hasSizeLadder,
1015
1028
  hlsLadderAlignment,
1016
1029
  invalidateSlotCache2 as invalidateSlotCache,
1030
+ isImageRole,
1017
1031
  isRequestablePreset2 as isRequestablePreset,
1018
1032
  isUniversallyPlayableAudio,
1019
1033
  iteratePaletteSwatches,