@nitida/sdk 0.26.0 → 0.27.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/dist/web.js CHANGED
@@ -15,11 +15,22 @@ import {
15
15
  setCdnBase,
16
16
  setTenantId
17
17
  } from "@nitida/asset-client";
18
+
19
+ // src/audio-compat.ts
20
+ function isUniversallyPlayableAudio(mime) {
21
+ const base = (mime.split(";")[0] ?? "").trim().toLowerCase();
22
+ return base === "audio/mpeg" || base === "audio/mp4" || base === "audio/aac";
23
+ }
24
+
25
+ // src/index.ts
18
26
  import {
27
+ accessMessage,
28
+ assertPublic,
19
29
  bestTextContrast,
20
30
  computeVariantDimensions,
21
31
  configureSlotResolver as configureSlotResolver2,
22
32
  contrastRatio,
33
+ deriveAccessKey,
23
34
  extractAssetSha,
24
35
  getAmbientGradient,
25
36
  getAssetDimensions,
@@ -30,6 +41,8 @@ import {
30
41
  getHlsStreamingUrl as getHlsStreamingUrl2,
31
42
  getPaletteBlurBackground,
32
43
  getPaletteCssVars,
44
+ getPrivateAssetUrl,
45
+ getPrivateTransformUrl,
33
46
  getSignedTransformUrl as getSignedTransformUrl2,
34
47
  getTenantId,
35
48
  getTextColorForBackground,
@@ -51,6 +64,7 @@ import {
51
64
  serializeTransform,
52
65
  setCdnBase as setCdnBase2,
53
66
  setTenantId as setTenantId2,
67
+ signAccessUrl,
54
68
  signTransformUrl,
55
69
  TRANSFORM_WIDTHS
56
70
  } from "@nitida/asset-client";
@@ -256,9 +270,10 @@ var AssetsApi = class {
256
270
  return Array.isArray(dto.variants) ? dto.variants : [];
257
271
  }
258
272
  /**
259
- * Add or rebuild variants on an existing asset. Image presets are
260
- * MERGED with what's there passing `{ presets: ["thumb"] }` adds
261
- * the thumb variant without touching `lg`, `sm`, `original`, etc.
273
+ * Add or rebuild variants on an existing asset. Presets are MERGED
274
+ * with what's there, for images AND for video passing
275
+ * `{ presets: ["thumb"] }` adds the thumb variant without touching
276
+ * `lg`, `sm`, `original`, etc.
262
277
  *
263
278
  * // Day 0: upload original-only logo
264
279
  * const { assetId } = await aq.upload(logoFile); // defaults to ["original"]
@@ -277,10 +292,18 @@ var AssetsApi = class {
277
292
  * reading the source bytes from the permanent `original` variant —
278
293
  * no need to re-upload.
279
294
  *
280
- * Video presets are filtered to `["poster","video","aiproxy"]` and
281
- * dispatched to a background job (the call returns immediately
295
+ * Video presets are filtered to `["poster","video","aiproxy","probe"]`
296
+ * and dispatched to a background job (the call returns immediately
282
297
  * with a dispatch handle; poll `aq.assets.get(id).status` for
283
298
  * completion).
299
+ *
300
+ * ⚠️ Before 2026-08-22 the video path REPLACED the whole variant
301
+ * registry instead of merging, so a partial regenerate silently
302
+ * deregistered `poster`, `video` and — irrecoverably — `hls`, which
303
+ * is not a {@link RequestablePreset} and therefore cannot be asked
304
+ * for again. The objects kept serving from the CDN; only the
305
+ * registry died. Fixed server-side; a client on an older server
306
+ * still loses them.
284
307
  */
285
308
  async regenerate(assetId, opts = {}) {
286
309
  const r = await fetch(
@@ -548,7 +571,7 @@ var NitidaClient = class {
548
571
  }
549
572
  if (!this.opts.signingKey) {
550
573
  throw new Error(
551
- "aq.transform({ sign: true }) requires `signingKey` in NitidaClientOptions. Pull the tenant's signing key from /admin/tenants/:id and pass it to the SDK constructor on a SERVER-side instance only."
574
+ "aq.transform({ sign: true }) requires `signingKey` in NitidaClientOptions. No signingKey on this client. The key is minted by POST /admin/projects/:code/rotate-signing-key, which needs a system-scope credential the platform operator holds \u2014 your own admin key gets 403 SYSTEM_KEY_REQUIRED, so ask for it. Then pass it to the SDK constructor on a SERVER-side instance only."
552
575
  );
553
576
  }
554
577
  return getSignedTransformUrl(asset, opts, this.opts.signingKey) ?? Promise.resolve(this.urlFor(asset, "lg"));
@@ -800,12 +823,30 @@ var NitidaClient = class {
800
823
  * `presets` string. Falls back through the preference order
801
824
  * lg → md → sm → thumb → original (for images)
802
825
  * video → poster (for videos)
803
- * mp3original (for audio)
826
+ * originalmp3 (for audio ALREADY playable everywhere)
827
+ * mp3 → original (for any other audio)
804
828
  * so an upload that was processed with e.g. `["original"]` still
805
829
  * returns a non-404 URL in `aq.upload`'s result.
830
+ *
831
+ * ⭐ Why audio branches on the source mime (changed 2026-08-22).
832
+ *
833
+ * It used to be `mp3 → original` unconditionally, so `upload().cdnUrl`
834
+ * handed back the server's auto-generated mp3 — libmp3lame, mono ~96 kbps —
835
+ * even when the caller had uploaded an MP3 or an AAC that already plays in
836
+ * every target browser. A consumer asking for "my file" silently received a
837
+ * re-encoded, lower-quality one, with no error to notice.
838
+ *
839
+ * Measured across the platform: of 126 audio assets carrying an mp3 variant,
840
+ * **105 had an `audio/mpeg` source** — an MP3 re-encoded into an MP3, for
841
+ * zero compatibility gain.
842
+ *
843
+ * The mp3 still wins for `audio/webm`/Opus and anything exotic, which is the
844
+ * case it was built for: Chrome records webm/Opus, which iOS Safari cannot
845
+ * decode. That guarantee is preserved exactly; only the needless downgrade
846
+ * is gone.
806
847
  */
807
848
  bestPresetForAsset(asset, mime) {
808
- const order = mime.startsWith("video/") ? ["video", "poster"] : mime.startsWith("audio/") ? ["mp3", "original"] : ["lg", "md", "sm", "thumb", "xl", "original"];
849
+ const order = mime.startsWith("video/") ? ["video", "poster"] : mime.startsWith("audio/") ? isUniversallyPlayableAudio(mime) ? ["original", "mp3"] : ["mp3", "original"] : ["lg", "md", "sm", "thumb", "xl", "original"];
809
850
  return order.find((p) => hasPreset(asset, p)) ?? this.defaultPresetForMime(mime);
810
851
  }
811
852
  };
@@ -879,12 +920,15 @@ export {
879
920
  PRESET_MAX_DIM,
880
921
  PRESET_SHORT,
881
922
  TRANSFORM_WIDTHS,
923
+ accessMessage,
924
+ assertPublic,
882
925
  bestTextContrast,
883
926
  compressImage,
884
927
  compressImages,
885
928
  computeVariantDimensions,
886
929
  configureSlotResolver2 as configureSlotResolver,
887
930
  contrastRatio,
931
+ deriveAccessKey,
888
932
  extractAssetSha,
889
933
  getAmbientGradient,
890
934
  getAssetDimensions,
@@ -895,6 +939,8 @@ export {
895
939
  getHlsStreamingUrl2 as getHlsStreamingUrl,
896
940
  getPaletteBlurBackground,
897
941
  getPaletteCssVars,
942
+ getPrivateAssetUrl,
943
+ getPrivateTransformUrl,
898
944
  getSignedTransformUrl2 as getSignedTransformUrl,
899
945
  getTenantId,
900
946
  getTextColorForBackground,
@@ -904,6 +950,7 @@ export {
904
950
  hasPreset2 as hasPreset,
905
951
  hlsLadderAlignment,
906
952
  invalidateSlotCache2 as invalidateSlotCache,
953
+ isUniversallyPlayableAudio,
907
954
  iteratePaletteSwatches,
908
955
  mimeFromFileName,
909
956
  pickAmbientBackground,
@@ -913,6 +960,7 @@ export {
913
960
  serializeTransform,
914
961
  setCdnBase2 as setCdnBase,
915
962
  setTenantId2 as setTenantId,
963
+ signAccessUrl,
916
964
  signTransformUrl
917
965
  };
918
966
  //# sourceMappingURL=web.js.map