@nitida/asset-client 0.20.3 → 0.20.4

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/src/index.ts CHANGED
@@ -878,11 +878,30 @@ export async function getPrivateTransformUrl(
878
878
  * ```
879
879
  */
880
880
  export function hasPreset(
881
- asset: Pick<AssetDTO, "presets">,
881
+ asset: { presets?: string | null },
882
882
  preset: VariantPreset,
883
883
  ): boolean {
884
- if (preset === "mp3") return asset.presets.includes("mp3");
885
- return stripMultiCharTokens(asset.presets).includes(PRESET_SHORT[preset]);
884
+ // ⭐⭐ `presets` PUEDE FALTAR, Y ASUMIR QUE NO ERA UN CRASH EN PRODUCCIÓN
885
+ //
886
+ // El DTO que `assets.byHash(sha)` devuelve no siempre trae `presets` — igual
887
+ // que no traía `sha`. Y `upload()` le pasa ese DTO crudo a `bestPresetForAsset`
888
+ // → `hasPreset` → acá. Con `presets` ausente, `asset.presets.includes(...)`
889
+ // y `stripMultiCharTokens(asset.presets)` reventaban con
890
+ // `undefined is not an object (evaluating 'presets.replace')`.
891
+ //
892
+ // Medido en el canario de neo 2026-08-25: verde con 0.30.2, rojo con 0.32.2,
893
+ // en la rama ORDINARIA del dedup (`existing.status === "ready"`) — o sea toda
894
+ // re-subida de bytes que ya existen, no el caso raro de ayer.
895
+ //
896
+ // ⭐ La invariante que faltaba no era «el objeto lleva `sha`» sino «todo
897
+ // objeto que `upload()` le pasa a un helper satisface la forma que el helper
898
+ // asume». Se arregla ensanchando la forma del helper —`presets` opcional—, no
899
+ // parcheando cada llamador de a uno. Un `presets` ausente significa «no sé qué
900
+ // variantes tiene», que es `false` para cualquier preset: el llamador cae a su
901
+ // default, que es lo correcto.
902
+ const presets = asset.presets ?? "";
903
+ if (preset === "mp3") return presets.includes("mp3");
904
+ return stripMultiCharTokens(presets).includes(PRESET_SHORT[preset]);
886
905
  }
887
906
 
888
907
  /**
@@ -909,8 +928,8 @@ export function hasPreset(
909
928
  * keep sending them, and this is the check every guide points at as the
910
929
  * reliable one. Order matters — strip the longest tokens first.
911
930
  */
912
- function stripMultiCharTokens(presets: string): string {
913
- return presets
931
+ function stripMultiCharTokens(presets: string | null | undefined): string {
932
+ return (presets ?? "")
914
933
  .replace(/transform-[0-9a-f]*/g, "")
915
934
  .replace(/upscale_[a-z0-9_]*/g, "")
916
935
  .replace(/mp3/g, "")