@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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4354](https://github.com/snowcone-app/snowcone-monorepo/pull/4354) [`426ba73`](https://github.com/snowcone-app/snowcone-monorepo/commit/426ba73e27630f48c0c673a9f3510bc0c14540ab) Thanks [@kevinsproles](https://github.com/kevinsproles)! - `rerender` requests are paced to the render box's limit (one per 550 ms): failures inside the interval wait and go out as one request, instead of being refused with E_RERENDER_RATE_LIMITED and falling back to configs.
|
|
8
|
+
|
|
9
|
+
## 0.9.5
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#4351](https://github.com/snowcone-app/snowcone-monorepo/pull/4351) [`f9910a8`](https://github.com/snowcone-app/snowcone-monorepo/commit/f9910a86ec7d3ee48d9d4fbd5099f4790ce91e98) Thanks [@kevinsproles](https://github.com/kevinsproles)! - A cropped frame whose blob: URL was already revoked (its newer frame reached the SDK before React state delivered it) no longer switches the session to full-frame delivery: it waits up to 2 s for the newer frame, and only counts as a real failure if none arrives.
|
|
14
|
+
|
|
3
15
|
## 0.9.4
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -6062,6 +6062,8 @@ async function compositeCroppedFrame(args) {
|
|
|
6062
6062
|
var import_jsx_runtime52 = require("react/jsx-runtime");
|
|
6063
6063
|
var DEFAULT_ARTBOARD_SIZE = 2e3;
|
|
6064
6064
|
var MAX_CONCURRENT_BLOBS = 5;
|
|
6065
|
+
var FRAME_SUPERSEDE_GRACE_MS = 2e3;
|
|
6066
|
+
var RERENDER_MIN_INTERVAL_MS = 550;
|
|
6065
6067
|
function mergeMockupIds(current, extra) {
|
|
6066
6068
|
const out = [...current];
|
|
6067
6069
|
for (const id of extra) if (!out.includes(id)) out.push(id);
|
|
@@ -6219,6 +6221,9 @@ function RealtimeProvider({
|
|
|
6219
6221
|
const serverStampsVersionsRef = (0, import_react25.useRef)(false);
|
|
6220
6222
|
const pendingRerenderRef = (0, import_react25.useRef)([]);
|
|
6221
6223
|
const forceRerenderByConfigRef = (0, import_react25.useRef)(null);
|
|
6224
|
+
const lastRerenderAtRef = (0, import_react25.useRef)(0);
|
|
6225
|
+
const rerenderQueueRef = (0, import_react25.useRef)([]);
|
|
6226
|
+
const rerenderTimerRef = (0, import_react25.useRef)(null);
|
|
6222
6227
|
const fullFrameRerenderIdsRef = (0, import_react25.useRef)(/* @__PURE__ */ new Set());
|
|
6223
6228
|
const fullFrameRerenderTimerRef = (0, import_react25.useRef)(null);
|
|
6224
6229
|
(0, import_react25.useEffect)(
|
|
@@ -6301,6 +6306,28 @@ function RealtimeProvider({
|
|
|
6301
6306
|
[sendFullFrameConfig]
|
|
6302
6307
|
);
|
|
6303
6308
|
forceRerenderByConfigRef.current = forceRerenderByConfig;
|
|
6309
|
+
const sendRerenderPaced = (0, import_react25.useCallback)(
|
|
6310
|
+
(ids) => {
|
|
6311
|
+
rerenderQueueRef.current = mergeMockupIds(rerenderQueueRef.current, ids);
|
|
6312
|
+
if (rerenderTimerRef.current) return;
|
|
6313
|
+
const wait = Math.max(0, lastRerenderAtRef.current + RERENDER_MIN_INTERVAL_MS - Date.now());
|
|
6314
|
+
const flush = () => {
|
|
6315
|
+
rerenderTimerRef.current = null;
|
|
6316
|
+
const batch = rerenderQueueRef.current;
|
|
6317
|
+
rerenderQueueRef.current = [];
|
|
6318
|
+
if (batch.length === 0) return;
|
|
6319
|
+
lastRerenderAtRef.current = Date.now();
|
|
6320
|
+
pendingRerenderRef.current = mergeMockupIds(pendingRerenderRef.current, batch);
|
|
6321
|
+
if (!rerenderRaw(batch)) {
|
|
6322
|
+
pendingRerenderRef.current = [];
|
|
6323
|
+
forceRerenderByConfigRef.current?.(batch);
|
|
6324
|
+
}
|
|
6325
|
+
};
|
|
6326
|
+
if (wait === 0) flush();
|
|
6327
|
+
else rerenderTimerRef.current = setTimeout(flush, wait);
|
|
6328
|
+
},
|
|
6329
|
+
[rerenderRaw]
|
|
6330
|
+
);
|
|
6304
6331
|
const rerenderFullFrame = (0, import_react25.useCallback)(
|
|
6305
6332
|
(mockupId) => {
|
|
6306
6333
|
fullFrameRerenderIdsRef.current.add(mockupId);
|
|
@@ -6321,14 +6348,13 @@ function RealtimeProvider({
|
|
|
6321
6348
|
}
|
|
6322
6349
|
if (serverStampsVersionsRef.current) {
|
|
6323
6350
|
sendFullFrameConfig(ids);
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
pendingRerenderRef.current = [];
|
|
6351
|
+
sendRerenderPaced(failed);
|
|
6352
|
+
return;
|
|
6327
6353
|
}
|
|
6328
6354
|
forceRerenderByConfig(failed);
|
|
6329
6355
|
}, 0);
|
|
6330
6356
|
},
|
|
6331
|
-
[sendFullFrameConfig, forceRerenderByConfig,
|
|
6357
|
+
[sendFullFrameConfig, forceRerenderByConfig, sendRerenderPaced]
|
|
6332
6358
|
);
|
|
6333
6359
|
const maybeFlipCrop = (0, import_react25.useCallback)(() => {
|
|
6334
6360
|
if (!croppedDeliveryEnabled || !cropCapableRef.current) return;
|
|
@@ -6454,6 +6480,22 @@ function RealtimeProvider({
|
|
|
6454
6480
|
if (gen !== sceneGenRef.current || compositeQueueRef.current.has(result.mockupId) || processedFrameRef.current.get(result.mockupId) !== result.imageUrl) {
|
|
6455
6481
|
return;
|
|
6456
6482
|
}
|
|
6483
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6484
|
+
if (result.imageUrl.startsWith("blob:") && message.startsWith("E_OVERLAY_FRAME_LOAD") && message.includes(result.imageUrl.slice(0, 160))) {
|
|
6485
|
+
const failedUrl = result.imageUrl;
|
|
6486
|
+
setTimeout(() => {
|
|
6487
|
+
if (gen !== sceneGenRef.current) return;
|
|
6488
|
+
if (compositeQueueRef.current.has(result.mockupId)) return;
|
|
6489
|
+
if (processedFrameRef.current.get(result.mockupId) !== failedUrl) return;
|
|
6490
|
+
console.error(
|
|
6491
|
+
`[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.`,
|
|
6492
|
+
err
|
|
6493
|
+
);
|
|
6494
|
+
cropCapableRef.current = false;
|
|
6495
|
+
rerenderFullFrame(result.mockupId);
|
|
6496
|
+
}, FRAME_SUPERSEDE_GRACE_MS);
|
|
6497
|
+
return;
|
|
6498
|
+
}
|
|
6457
6499
|
console.error(
|
|
6458
6500
|
"[RealtimeProvider] E_OVERLAY_COMPOSITE_FAILED: cropped-frame composite failed \u2014 full-frame delivery for the rest of this session.",
|
|
6459
6501
|
err
|