@floegence/redevplugin-ui 3.0.19 → 3.0.21
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/surface.js +39 -9
- package/package.json +2 -2
package/dist/surface.js
CHANGED
|
@@ -751,6 +751,7 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
751
751
|
const maxImageTotalPixels = ${opaqueSurfaceRenderLimits.max_image_total_pixels};
|
|
752
752
|
const workerHeartbeatIntervalMs = ${opaqueSurfaceRenderLimits.worker_heartbeat_interval_ms};
|
|
753
753
|
const workerHeartbeatTimeoutMs = ${opaqueSurfaceRenderLimits.worker_heartbeat_timeout_ms};
|
|
754
|
+
const rendererCommitFallbackMs = 100;
|
|
754
755
|
const maxCriticalDocumentBytes = ${8 * 1024 * 1024};
|
|
755
756
|
const maxPrivateAssetBase64Length = ${Math.ceil((32 * 1024 * 1024) / 3) * 4};
|
|
756
757
|
const maxLazyAssetCount = ${maxOpaqueSurfaceLazyAssets};
|
|
@@ -863,7 +864,9 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
863
864
|
let workerHeartbeatTimer;
|
|
864
865
|
let workerHeartbeatTimeout;
|
|
865
866
|
let pendingQuiesceID;
|
|
867
|
+
let runtimeDisposed = false;
|
|
866
868
|
const pendingWorkerRequests = new Set();
|
|
869
|
+
const pendingRendererCommits = new Set();
|
|
867
870
|
const requestSequence = { rpc: 0, execution: 0, render: 0, canvas: 0, asset: 0 };
|
|
868
871
|
let executionQuerySurfaceTokens = 8;
|
|
869
872
|
let executionQuerySurfaceRefillAt = performance.now();
|
|
@@ -956,7 +959,13 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
956
959
|
sendParent({ type: "redevplugin.surface.error", error: String(message).slice(0, 512) });
|
|
957
960
|
disposeRuntime();
|
|
958
961
|
};
|
|
962
|
+
const cancelPendingRendererCommits = () => {
|
|
963
|
+
for (const cancel of [...pendingRendererCommits]) cancel();
|
|
964
|
+
};
|
|
959
965
|
const disposeRuntime = () => {
|
|
966
|
+
if (runtimeDisposed) return;
|
|
967
|
+
runtimeDisposed = true;
|
|
968
|
+
cancelPendingRendererCommits();
|
|
960
969
|
if (workerHeartbeatTimer) clearTimeout(workerHeartbeatTimer);
|
|
961
970
|
if (workerHeartbeatTimeout) clearTimeout(workerHeartbeatTimeout);
|
|
962
971
|
workerHeartbeatTimer = undefined;
|
|
@@ -997,6 +1006,7 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
997
1006
|
assetByLogicalID.clear();
|
|
998
1007
|
};
|
|
999
1008
|
const terminateQuiescedWorker = () => {
|
|
1009
|
+
cancelPendingRendererCommits();
|
|
1000
1010
|
if (workerHeartbeatTimer) clearTimeout(workerHeartbeatTimer);
|
|
1001
1011
|
if (workerHeartbeatTimeout) clearTimeout(workerHeartbeatTimeout);
|
|
1002
1012
|
workerHeartbeatTimer = undefined;
|
|
@@ -1486,9 +1496,25 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
1486
1496
|
parent.insertBefore(target, before || null);
|
|
1487
1497
|
}
|
|
1488
1498
|
};
|
|
1489
|
-
const
|
|
1490
|
-
|
|
1491
|
-
|
|
1499
|
+
const commitOnRenderOpportunity = (commit) => new Promise((resolve, reject) => {
|
|
1500
|
+
if (runtimeDisposed) return resolve(false);
|
|
1501
|
+
let settled = false;
|
|
1502
|
+
let frameID;
|
|
1503
|
+
let fallbackTimer;
|
|
1504
|
+
const finish = (shouldCommit) => {
|
|
1505
|
+
if (settled) return;
|
|
1506
|
+
settled = true;
|
|
1507
|
+
if (frameID !== undefined) cancelAnimationFrame(frameID);
|
|
1508
|
+
if (fallbackTimer !== undefined) clearTimeout(fallbackTimer);
|
|
1509
|
+
pendingRendererCommits.delete(cancel);
|
|
1510
|
+
if (!shouldCommit || runtimeDisposed) return resolve(false);
|
|
1511
|
+
try { commit(); resolve(true); } catch (error) { reject(error); }
|
|
1512
|
+
};
|
|
1513
|
+
const cancel = () => finish(false);
|
|
1514
|
+
pendingRendererCommits.add(cancel);
|
|
1515
|
+
frameID = requestAnimationFrame(() => finish(true));
|
|
1516
|
+
fallbackTimer = setTimeout(() => finish(true), rendererCommitFallbackMs);
|
|
1517
|
+
});
|
|
1492
1518
|
const mountWorkerTree = async (tree) => {
|
|
1493
1519
|
if (uiRevision !== 0) throw new Error("plugin UI mount may only occur once");
|
|
1494
1520
|
const built = buildWorkerSubtree(tree, { nodes: 0 }, 1, undefined);
|
|
@@ -1496,25 +1522,29 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
1496
1522
|
if (!(root instanceof Element)) throw new Error("plugin UI root must be an element");
|
|
1497
1523
|
validateCanvasIdentifiers(root);
|
|
1498
1524
|
const renderState = captureRenderState();
|
|
1499
|
-
await
|
|
1525
|
+
const committed = await commitOnRenderOpportunity(() => {
|
|
1500
1526
|
document.body.replaceChildren(root);
|
|
1501
1527
|
restoreRenderState(renderState);
|
|
1502
1528
|
});
|
|
1529
|
+
if (!committed) return false;
|
|
1503
1530
|
uiGraph = built.graph;
|
|
1504
1531
|
uiNodes = built.nodes;
|
|
1505
1532
|
uiRevision = 1;
|
|
1506
1533
|
sendParent({ type: "redevplugin.surface.first_commit" });
|
|
1534
|
+
return true;
|
|
1507
1535
|
};
|
|
1508
1536
|
const patchWorkerTree = async (baseRevision, revision, operations) => {
|
|
1509
1537
|
if (uiRevision < 1 || baseRevision !== uiRevision || revision !== baseRevision + 1) throw new Error("plugin UI patch revision is invalid");
|
|
1510
1538
|
const validated = validatePatch(operations);
|
|
1511
1539
|
const renderState = captureRenderState();
|
|
1512
|
-
await
|
|
1540
|
+
const committed = await commitOnRenderOpportunity(() => {
|
|
1513
1541
|
for (const operation of validated.plan) applyPatchOperation(operation);
|
|
1514
1542
|
validated.graph.commit();
|
|
1515
1543
|
restoreRenderState(renderState);
|
|
1516
1544
|
});
|
|
1545
|
+
if (!committed) return false;
|
|
1517
1546
|
uiRevision = revision;
|
|
1547
|
+
return true;
|
|
1518
1548
|
};
|
|
1519
1549
|
const actionPayload = (event, element, eventType = event.type) => {
|
|
1520
1550
|
const target = event.target instanceof Element ? event.target.closest("[data-redevplugin-key]") : element;
|
|
@@ -2272,9 +2302,9 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
2272
2302
|
completeWorkerRequest(message.id);
|
|
2273
2303
|
return rejectWorkerRequest(message.id, "plugin render rate limit exceeded");
|
|
2274
2304
|
}
|
|
2275
|
-
void mountWorkerTree(message.tree).then(() => {
|
|
2305
|
+
void mountWorkerTree(message.tree).then((committed) => {
|
|
2276
2306
|
completeWorkerRequest(message.id);
|
|
2277
|
-
sendWorker({ type: "redevplugin.bridge.response", id: message.id, ok: true });
|
|
2307
|
+
if (committed) sendWorker({ type: "redevplugin.bridge.response", id: message.id, ok: true });
|
|
2278
2308
|
}, (error) => fail(error && error.message || "plugin UI mount violated the protocol"));
|
|
2279
2309
|
return;
|
|
2280
2310
|
}
|
|
@@ -2285,9 +2315,9 @@ export function createOpaquePluginBootstrapHTML(options = {}) {
|
|
|
2285
2315
|
completeWorkerRequest(message.id);
|
|
2286
2316
|
return rejectWorkerRequest(message.id, "plugin render rate limit exceeded");
|
|
2287
2317
|
}
|
|
2288
|
-
void patchWorkerTree(message.base_revision, message.revision, message.operations).then(() => {
|
|
2318
|
+
void patchWorkerTree(message.base_revision, message.revision, message.operations).then((committed) => {
|
|
2289
2319
|
completeWorkerRequest(message.id);
|
|
2290
|
-
sendWorker({ type: "redevplugin.bridge.response", id: message.id, ok: true });
|
|
2320
|
+
if (committed) sendWorker({ type: "redevplugin.bridge.response", id: message.id, ok: true });
|
|
2291
2321
|
}, (error) => fail(error && error.message || "plugin UI patch violated the protocol"));
|
|
2292
2322
|
return;
|
|
2293
2323
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floegence/redevplugin-ui",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.21",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"dist"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@floegence/redevplugin-contracts": "3.0.
|
|
43
|
+
"@floegence/redevplugin-contracts": "3.0.21"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|