@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/CHANGELOG.md +12 -0
- package/dist/index.cjs +46 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +46 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/patterns/RealtimeProvider.tsx +67 -4
- package/src/patterns/__tests__/RealtimeProvider.cropDelivery.test.tsx +65 -0
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
|
-
|
|
5966
|
-
|
|
5967
|
-
pendingRerenderRef.current = [];
|
|
5992
|
+
sendRerenderPaced(failed);
|
|
5993
|
+
return;
|
|
5968
5994
|
}
|
|
5969
5995
|
forceRerenderByConfig(failed);
|
|
5970
5996
|
}, 0);
|
|
5971
5997
|
},
|
|
5972
|
-
[sendFullFrameConfig, forceRerenderByConfig,
|
|
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
|