PluginProbe
ZIP AI – AI Website Builder & AI Agent / 0.0.13
ZIP AI – AI Website Builder & AI Agent v0.0.13
0.0.14 0.0.13 0.0.12 0.0.11 0.0.10 0.0.9 trunk 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8
zip-ai / assets / js / core / rpc-dedup.js

rpc-dedup.js in ZIP AI – AI Website Builder & AI Agent 0.0.13, at assets/js/core/rpc-dedup.js

69 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * ZipWP MCP — pure js_rpc dispatch-dedup decision (B-1 / P5).
3 *
4 * The bridge's executeTools loop owns the seen-map I/O (sessionStorage-backed,
5 * FIFO-bounded). THIS module is the pure DECISION over a prior seen entry, so the
6 * idempotency logic — the silent-until-it-bites duplicate-content path — is
7 * unit-tested instead of living only inline in the browser IIFE.
8 *
9 * Decisions, given the prior _rpcSeen entry for a js_rpc call_id (or undefined):
10 * - a prior entry (IN-FLIGHT or COMPLETED) → repost_cached: NEVER re-dispatch
11 * (re-running the handler double-applies the mutation); re-POST the stored
12 * reply so a still-waiting brain BRPOP resolves.
13 * - no prior entry → run: the caller records IN_FLIGHT_MARKER BEFORE the handler
14 * mutates the tree, so a crash BETWEEN the mutation and the completion-record
15 * still leaves a marker. A replay then reposts an uncertain (ok:false) reply
16 * and the brain verifies with get_context before any retry — never a blind
17 * re-dispatch.
18 *
19 * Dual-mode: window.zipwpRpcDedup in the browser; CommonJS for jest.
20 *
21 * @package
22 */
23 ( function () {
24 'use strict';
25
26 // The reply a replay receives while the first run is mid-apply, or after a
27 // crash before the completion-record. ok:false → the brain treats it as an
28 // unconfirmed apply (verify-before-retry), never a blind re-apply.
29 const IN_FLIGHT_MARKER = { ok: false, data: undefined, error: 'apply_pending_no_confirmation' };
30
31 // A COMPLETED session-scoped write (apply_change / set_scripts — both mutate
32 // block attributes in the OPEN editor session) cached on a PRIOR page load: the
33 // page reloaded since, and Gutenberg DISCARDS unsaved session edits on reload.
34 // The cached ok:true would then mask a LOST edit (the brain folds success while
35 // the page reverted). Repost this uncertain reply so the brain re-verifies with
36 // get_context instead — same "don't assume, verify" contract as IN_FLIGHT.
37 const RELOAD_REVERIFY_MARKER = { ok: false, data: undefined, error: 'apply_unconfirmed_after_reload' };
38
39 // `currentPageLoadId` is the token minted once per page load. A cached entry
40 // tagged `mutating` (a session-scoped write) whose `pageLoadId` differs means a
41 // reload happened between the apply and this replay → the edit is gone.
42 function decideJsRpcDispatch( seenEntry, currentPageLoadId ) {
43 if ( seenEntry ) {
44 if ( seenEntry.mutating === true &&
45 currentPageLoadId !== undefined && currentPageLoadId !== null &&
46 seenEntry.pageLoadId !== undefined &&
47 seenEntry.pageLoadId !== currentPageLoadId ) {
48 return { action: 'repost_cached', reply: RELOAD_REVERIFY_MARKER };
49 }
50 return { action: 'repost_cached', reply: seenEntry };
51 }
52 return { action: 'run', inFlightMarker: IN_FLIGHT_MARKER };
53 }
54
55 if ( typeof window !== 'undefined' ) {
56 window.zipwpRpcDedup = window.zipwpRpcDedup || {};
57 window.zipwpRpcDedup.decideJsRpcDispatch = decideJsRpcDispatch;
58 window.zipwpRpcDedup.IN_FLIGHT_MARKER = IN_FLIGHT_MARKER;
59 window.zipwpRpcDedup.RELOAD_REVERIFY_MARKER = RELOAD_REVERIFY_MARKER;
60 }
61 if ( typeof module !== 'undefined' && module.exports ) {
62 module.exports = {
63 decideJsRpcDispatch,
64 IN_FLIGHT_MARKER,
65 RELOAD_REVERIFY_MARKER,
66 };
67 }
68 }() );
69