@ai-matrx/media 0.5.11 → 0.6.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/react.js CHANGED
@@ -725,7 +725,7 @@ function useMediaLoadRecovery(src, options) {
725
725
  const recoverable = options?.recoverable !== false;
726
726
  const onTerminal = options?.onTerminal;
727
727
  const failureRef = options?.failureRef;
728
- const [result, setResult] = useState3({ source: src, retryKey: 0, failed: false });
728
+ const [result, setResult] = useState3({ source: src, retryKey: 0, failed: false, healedSrc: null });
729
729
  const attemptRef = useRef3(0);
730
730
  const recoveryInFlightRef = useRef3(false);
731
731
  useEffect3(() => {
@@ -739,7 +739,7 @@ function useMediaLoadRecovery(src, options) {
739
739
  const onLoadError = (event) => {
740
740
  if (recoveryInFlightRef.current) return;
741
741
  if (!src || !recoverable) {
742
- setResult({ source: src, retryKey: 0, failed: true });
742
+ setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
743
743
  if (src) {
744
744
  capture({
745
745
  phase: "element-load",
@@ -770,23 +770,90 @@ function useMediaLoadRecovery(src, options) {
770
770
  setResult((current) => ({
771
771
  source: src,
772
772
  retryKey: current.source === src ? current.retryKey + 1 : 1,
773
- failed: false
773
+ failed: false,
774
+ healedSrc: null
774
775
  }));
775
- } else {
776
- setResult({ source: src, retryKey: 0, failed: true });
776
+ return;
777
+ }
778
+ const lane1 = {
779
+ lane: "session-refresh-retry",
780
+ outcome: attempt > 1 ? "http-error" : "unavailable",
781
+ ms: 0,
782
+ ...report.status !== void 0 ? { status: report.status } : {},
783
+ detail: attempt > 1 ? "cookie re-minted, same durable URL retried in the element, element errored again" : "recovery declined on the first attempt (no usable session)"
784
+ };
785
+ if (!failureRef || !client.healLoadError) {
786
+ setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
777
787
  capture({
778
788
  phase: attempt > 1 ? "element-load" : "recovery",
779
789
  mediaRef: identity(),
780
790
  terminal: true,
781
791
  retryOutcome: attempt > 1 ? "retried" : "not-attempted",
782
- message: attempt > 1 ? "media element failed to load after the session-refresh retry" : "media load recovery declined on the first attempt (session refresh did not produce a usable session)",
792
+ message: (attempt > 1 ? "media element failed to load after the session-refresh retry" : "media load recovery declined on the first attempt (session refresh did not produce a usable session)") + (failureRef ? " \u2014 no heal ladder on this client (healLoadError not implemented)" : " \u2014 no durable ref supplied, so no heal lane could run"),
783
793
  ...report.status !== void 0 ? { status: report.status } : {}
784
794
  });
785
795
  onTerminal?.(event);
796
+ return;
786
797
  }
798
+ const heal = client.healLoadError(failureRef, {
799
+ src: mintDurableSrc(src),
800
+ attempts: [lane1]
801
+ });
802
+ heal.then(
803
+ (verdict) => {
804
+ if (verdict.src) {
805
+ setResult({
806
+ source: src,
807
+ retryKey: 0,
808
+ failed: false,
809
+ healedSrc: verdict.src
810
+ });
811
+ capture({
812
+ phase: "heal",
813
+ mediaRef: identity(),
814
+ terminal: false,
815
+ healed: true,
816
+ healedBy: verdict.healedBy,
817
+ attempts: verdict.attempts,
818
+ diagnosis: verdict.diagnosis,
819
+ retryOutcome: "retried",
820
+ message: `HEALED (${verdict.healedBy ?? "unknown lane"}): ${verdict.summary}`,
821
+ ...report.status !== void 0 ? { status: report.status } : {}
822
+ });
823
+ return;
824
+ }
825
+ setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
826
+ capture({
827
+ phase: "heal",
828
+ mediaRef: identity(),
829
+ terminal: true,
830
+ healed: false,
831
+ attempts: verdict.attempts,
832
+ diagnosis: verdict.diagnosis,
833
+ retryOutcome: "retried",
834
+ message: `DEAD after ${verdict.attempts.length} lane(s): ${verdict.summary}`,
835
+ ...report.status !== void 0 ? { status: report.status } : {}
836
+ });
837
+ onTerminal?.(event);
838
+ },
839
+ (err) => {
840
+ setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
841
+ capture({
842
+ phase: "heal",
843
+ mediaRef: identity(),
844
+ terminal: true,
845
+ healed: false,
846
+ attempts: [lane1],
847
+ diagnosis: "unknown",
848
+ retryOutcome: "recovery-failed",
849
+ message: `heal ladder threw: ${err instanceof Error ? err.message : String(err ?? "unknown error")}`
850
+ });
851
+ onTerminal?.(event);
852
+ }
853
+ );
787
854
  },
788
855
  (err) => {
789
- setResult({ source: src, retryKey: 0, failed: true });
856
+ setResult({ source: src, retryKey: 0, failed: true, healedSrc: null });
790
857
  capture({
791
858
  phase: "session",
792
859
  mediaRef: identity(),
@@ -801,7 +868,8 @@ function useMediaLoadRecovery(src, options) {
801
868
  return {
802
869
  retryKey: result.source === src ? result.retryKey : 0,
803
870
  onLoadError,
804
- failed: result.source === src ? result.failed : false
871
+ failed: result.source === src ? result.failed : false,
872
+ healedSrc: result.source === src ? result.healedSrc : null
805
873
  };
806
874
  }
807
875
 
@@ -1130,15 +1198,16 @@ function InlineMediaRef({
1130
1198
  resolution && (resolution.transport === "blob" || crossOrigin && resolution.isCdn !== true)
1131
1199
  );
1132
1200
  const blob = useMediaBlob(needsBlob ? mediaRef : null);
1133
- const url = needsBlob ? blob.url : resolution?.src ?? null;
1201
+ const resolvedUrl = needsBlob ? blob.url : resolution?.src ?? null;
1134
1202
  const terminalCallback = (event) => onError?.(
1135
1203
  event
1136
1204
  );
1137
- const recovery = useMediaLoadRecovery(url, {
1205
+ const recovery = useMediaLoadRecovery(resolvedUrl, {
1138
1206
  recoverable: resolution?.recoverable !== false,
1139
1207
  failureRef: mediaRef,
1140
1208
  onTerminal: terminalCallback
1141
1209
  });
1210
+ const url = recovery.healedSrc ?? resolvedUrl;
1142
1211
  const blobRecovery = useMediaBlobLoadRecovery(
1143
1212
  needsBlob ? mediaRef : null,
1144
1213
  needsBlob ? url : null,
@@ -1533,18 +1602,19 @@ function ImageThumb({
1533
1602
  blobRecovery,
1534
1603
  fallback
1535
1604
  }) {
1536
- const { retryKey, onLoadError, failed } = useMediaLoadRecovery(url, {
1605
+ const { retryKey, onLoadError, failed, healedSrc } = useMediaLoadRecovery(url, {
1537
1606
  recoverable,
1538
1607
  failureRef: mediaRef
1539
1608
  });
1540
1609
  const activeRecovery = blobBacked ? { retryKey: 0, ...blobRecovery } : { retryKey, onLoadError, failed };
1610
+ const renderUrl = !blobBacked && healedSrc || url;
1541
1611
  if (activeRecovery.failed) return /* @__PURE__ */ jsx4(Fragment2, { children: fallback });
1542
1612
  return /* @__PURE__ */ jsx4(
1543
1613
  "img",
1544
1614
  {
1545
- src: url,
1615
+ src: renderUrl,
1546
1616
  alt,
1547
- loading: url.startsWith("blob:") ? "eager" : "lazy",
1617
+ loading: renderUrl.startsWith("blob:") ? "eager" : "lazy",
1548
1618
  className: "h-full w-full object-cover",
1549
1619
  onError: activeRecovery.onLoadError
1550
1620
  },
@@ -1559,11 +1629,12 @@ function VideoPosterThumb({
1559
1629
  blobRecovery,
1560
1630
  fallback
1561
1631
  }) {
1562
- const { retryKey, onLoadError, failed } = useMediaLoadRecovery(url, {
1632
+ const { retryKey, onLoadError, failed, healedSrc } = useMediaLoadRecovery(url, {
1563
1633
  recoverable,
1564
1634
  failureRef: mediaRef
1565
1635
  });
1566
1636
  const activeRecovery = blobBacked ? { retryKey: 0, ...blobRecovery } : { retryKey, onLoadError, failed };
1637
+ const renderUrl = !blobBacked && healedSrc || url;
1567
1638
  const ref = useRef5(null);
1568
1639
  useEffect6(() => {
1569
1640
  const v = ref.current;
@@ -1582,7 +1653,7 @@ function VideoPosterThumb({
1582
1653
  "video",
1583
1654
  {
1584
1655
  ref,
1585
- src: url,
1656
+ src: renderUrl,
1586
1657
  className: "h-full w-full object-cover pointer-events-none",
1587
1658
  preload: "metadata",
1588
1659
  muted: true,