@snowcone-app/ui 0.9.4 → 0.9.6

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/index.js CHANGED
@@ -5703,6 +5703,8 @@ async function compositeCroppedFrame(args) {
5703
5703
  import { jsx as jsx52 } from "react/jsx-runtime";
5704
5704
  var DEFAULT_ARTBOARD_SIZE = 2e3;
5705
5705
  var MAX_CONCURRENT_BLOBS = 5;
5706
+ var FRAME_SUPERSEDE_GRACE_MS = 2e3;
5707
+ var RERENDER_MIN_INTERVAL_MS = 550;
5706
5708
  function mergeMockupIds(current, extra) {
5707
5709
  const out = [...current];
5708
5710
  for (const id of extra) if (!out.includes(id)) out.push(id);
@@ -5860,6 +5862,9 @@ function RealtimeProvider({
5860
5862
  const serverStampsVersionsRef = useRef12(false);
5861
5863
  const pendingRerenderRef = useRef12([]);
5862
5864
  const forceRerenderByConfigRef = useRef12(null);
5865
+ const lastRerenderAtRef = useRef12(0);
5866
+ const rerenderQueueRef = useRef12([]);
5867
+ const rerenderTimerRef = useRef12(null);
5863
5868
  const fullFrameRerenderIdsRef = useRef12(/* @__PURE__ */ new Set());
5864
5869
  const fullFrameRerenderTimerRef = useRef12(null);
5865
5870
  useEffect17(
@@ -5942,6 +5947,28 @@ function RealtimeProvider({
5942
5947
  [sendFullFrameConfig]
5943
5948
  );
5944
5949
  forceRerenderByConfigRef.current = forceRerenderByConfig;
5950
+ const sendRerenderPaced = useCallback10(
5951
+ (ids) => {
5952
+ rerenderQueueRef.current = mergeMockupIds(rerenderQueueRef.current, ids);
5953
+ if (rerenderTimerRef.current) return;
5954
+ const wait = Math.max(0, lastRerenderAtRef.current + RERENDER_MIN_INTERVAL_MS - Date.now());
5955
+ const flush = () => {
5956
+ rerenderTimerRef.current = null;
5957
+ const batch = rerenderQueueRef.current;
5958
+ rerenderQueueRef.current = [];
5959
+ if (batch.length === 0) return;
5960
+ lastRerenderAtRef.current = Date.now();
5961
+ pendingRerenderRef.current = mergeMockupIds(pendingRerenderRef.current, batch);
5962
+ if (!rerenderRaw(batch)) {
5963
+ pendingRerenderRef.current = [];
5964
+ forceRerenderByConfigRef.current?.(batch);
5965
+ }
5966
+ };
5967
+ if (wait === 0) flush();
5968
+ else rerenderTimerRef.current = setTimeout(flush, wait);
5969
+ },
5970
+ [rerenderRaw]
5971
+ );
5945
5972
  const rerenderFullFrame = useCallback10(
5946
5973
  (mockupId) => {
5947
5974
  fullFrameRerenderIdsRef.current.add(mockupId);
@@ -5962,14 +5989,13 @@ function RealtimeProvider({
5962
5989
  }
5963
5990
  if (serverStampsVersionsRef.current) {
5964
5991
  sendFullFrameConfig(ids);
5965
- pendingRerenderRef.current = failed;
5966
- if (rerenderRaw(failed)) return;
5967
- pendingRerenderRef.current = [];
5992
+ sendRerenderPaced(failed);
5993
+ return;
5968
5994
  }
5969
5995
  forceRerenderByConfig(failed);
5970
5996
  }, 0);
5971
5997
  },
5972
- [sendFullFrameConfig, forceRerenderByConfig, rerenderRaw]
5998
+ [sendFullFrameConfig, forceRerenderByConfig, sendRerenderPaced]
5973
5999
  );
5974
6000
  const maybeFlipCrop = useCallback10(() => {
5975
6001
  if (!croppedDeliveryEnabled || !cropCapableRef.current) return;
@@ -6095,6 +6121,22 @@ function RealtimeProvider({
6095
6121
  if (gen !== sceneGenRef.current || compositeQueueRef.current.has(result.mockupId) || processedFrameRef.current.get(result.mockupId) !== result.imageUrl) {
6096
6122
  return;
6097
6123
  }
6124
+ const message = err instanceof Error ? err.message : String(err);
6125
+ if (result.imageUrl.startsWith("blob:") && message.startsWith("E_OVERLAY_FRAME_LOAD") && message.includes(result.imageUrl.slice(0, 160))) {
6126
+ const failedUrl = result.imageUrl;
6127
+ setTimeout(() => {
6128
+ if (gen !== sceneGenRef.current) return;
6129
+ if (compositeQueueRef.current.has(result.mockupId)) return;
6130
+ if (processedFrameRef.current.get(result.mockupId) !== failedUrl) return;
6131
+ console.error(
6132
+ `[RealtimeProvider] E_OVERLAY_COMPOSITE_FAILED: frame for ${result.mockupId} failed to load and no newer frame arrived within ${FRAME_SUPERSEDE_GRACE_MS} ms \u2014 full-frame delivery for the rest of this session.`,
6133
+ err
6134
+ );
6135
+ cropCapableRef.current = false;
6136
+ rerenderFullFrame(result.mockupId);
6137
+ }, FRAME_SUPERSEDE_GRACE_MS);
6138
+ return;
6139
+ }
6098
6140
  console.error(
6099
6141
  "[RealtimeProvider] E_OVERLAY_COMPOSITE_FAILED: cropped-frame composite failed \u2014 full-frame delivery for the rest of this session.",
6100
6142
  err