resuma 1.1.0

Resuma — resumable SSR Rust web framework: zero hydration, islands, server actions, Flow (Axum).
1
function M(t){let e=new Map;for(let n of t){let r=h(n.id);e.set(r,wt(r,n.value))}return e}function h(t){return typeof t=="string"?t:typeof t=="number"?`s${t}`:`s${t[0]}`}function wt(t,e){let n=e,r=new Set,o={id:t,get value(){return n},set value(a){o.set(a)},set(a){Object.is(a,n)||(n=a,r.forEach(i=>i(n)))},update(a){let i=a(n);i!==void 0&&o.set(i)},subscribe(a){return r.add(a),()=>r.delete(a)}};return o}var bt="RESUMA-DYN",D=new WeakSet,j=new WeakSet,B=new WeakSet,U=new WeakSet,G=new WeakSet;function w(t,e){t.querySelectorAll(bt.toLowerCase()).forEach(r=>{if(D.has(r))return;let o=r.getAttribute("data-r-signal");if(!o)return;let a=e.get(o);a&&(r.textContent=E(a.value),a.subscribe(i=>{r.textContent=E(i)}),D.add(r))})}function b(t,e){t.querySelectorAll("[data-r-bind]").forEach(r=>V(r,e)),yt(t,e)}function yt(t,e){let n=document.createTreeWalker(t,NodeFilter.SHOW_ELEMENT),r=n.currentNode;for(;r;)r instanceof HTMLElement&&V(r,e),r=n.nextNode()}function vt(t){let e=t.toLowerCase();return e.startsWith("on")||e==="style"}var Et=new Set(["href","src","action","formaction","xlink:href","poster","background","ping","data"]);function St(t){let e=t.replace(/[\u0000-\u0020]+/g,"");return/^(?:javascript|vbscript|data):/i.test(e)?"":t}function V(t,e){if(j.has(t))return;let n=!1;for(let r of Array.from(t.attributes)){let o=r.name;if(!o.startsWith("data-r-bind:"))continue;let a=o.slice(12);if(vt(a))continue;let[i,s="{}"]=r.value.split("|"),c=e.get(i);if(!c)continue;let u=Et.has(a.toLowerCase()),d=l=>{let f=s.replace("{}",E(l));u&&(f=St(f)),t.setAttribute(a,f)};d(c.value),c.subscribe(d),n=!0}n&&j.add(t)}function E(t){if(t==null)return"";if(typeof t=="string")return t;if(typeof t=="number"||typeof t=="boolean")return String(t);try{return JSON.stringify(t)}catch{return String(t)}}function x(t,e){t.querySelectorAll("resuma-show").forEach(n=>{if(B.has(n))return;let r=n.getAttribute("data-r-show");if(!r)return;let o=n.getAttribute("data-r-inverted")==="true",a=n.querySelector("[data-r-show-if]"),i=n.querySelector("[data-r-show-else]"),s=e.get(r);if(!s||!a)return;let c=u=>{let d=o?!u:!!u;a.hidden=!d,i&&(i.hidden=d);let l=n.dataset.rPortalTarget,f=a.querySelector("template[data-r-portal]");if(!l&&f&&(l=f.getAttribute("data-r-portal")??void 0,l&&(n.dataset.rPortalTarget=l)),l){let g=document.getElementById(l)??document.querySelector(`[data-r-portal-target="${l}"]`);g&&(d?f&&kt(a):g.replaceChildren())}};c(s.value),s.subscribe(c),B.add(n)})}function kt(t){t.querySelectorAll("template[data-r-portal]").forEach(e=>{if(e.closest("[data-r-show-if]")?.hidden)return;let r=e.getAttribute("data-r-portal");if(!r)return;let o=document.getElementById(r)??document.querySelector(`[data-r-portal-target="${r}"]`);o&&o.replaceChildren(e.content.cloneNode(!0))})}function v(t){if(t&&typeof t=="object")for(let e of["title","name","label","text"]){let n=t[e];if(typeof n=="string")return n}return E(t)}function K(t){return t.hasAttribute("data-r-signal")}function Tt(t,e){w(t,e),b(t,e)}function Rt(t,e,n){if(n){let a=n.cloneNode(!0);if(a.setAttribute("data-r-for-key",e),a.removeAttribute("data-r-for-new"),a.querySelectorAll("resuma-dyn").forEach(i=>{K(i)||(i.textContent=v(t))}),!a.querySelector("resuma-dyn")){let i=a.querySelector(".todo-title");i&&(i.textContent=v(t))}return a}let r=document.createElement("div");r.setAttribute("data-r-for-item",""),r.setAttribute("data-r-for-key",e);let o=document.createElement("span");return o.textContent=v(t),r.appendChild(o),r}function Mt(t,e){if(t.querySelectorAll("resuma-dyn").forEach(n=>{K(n)||(n.textContent=v(e))}),!t.querySelector("resuma-dyn")){let n=t.querySelector(".todo-title");n&&(n.textContent=v(e))}}function Lt(t,e,n){if(e&&t&&typeof t=="object"){let r=t[e];if(r!=null)return String(r)}return String(n)}function _(t,e){t.querySelectorAll("resuma-for").forEach(n=>{if(U.has(n))return;let r=n.getAttribute("data-r-for");if(!r)return;let o=n.getAttribute("data-r-key"),a=n.querySelector("[data-r-for-list]"),i=e.get(r);if(!i||!a)return;let s=c=>{let u=Array.isArray(c)?c:[],d=new Map;a.querySelectorAll("[data-r-for-item]").forEach(m=>{let T=m.getAttribute("data-r-for-key");T&&d.set(T,m)});let l=[],f=document.createDocumentFragment(),g=a.querySelector("[data-r-for-item]:not([data-r-for-new])")??void 0;u.forEach((m,T)=>{let R=Lt(m,o,T);l.push(R);let y=d.get(R);y?(d.delete(R),Mt(y,m)):(y=Rt(m,R,g),y.setAttribute("data-r-for-new","true")),f.appendChild(y)}),a.replaceChildren(f),d.forEach(m=>m.remove()),Tt(a,e)};s(i.value),i.subscribe(s),U.add(n)})}function H(t,e){t.querySelectorAll("resuma-match").forEach(n=>{if(G.has(n))return;let r=n.getAttribute("data-r-match");if(!r)return;let o=e.get(r);if(!o)return;let a=n.querySelectorAll("[data-r-match-case]"),i=n.querySelector("[data-r-match-default]"),s=c=>{let u=typeof c=="string"?c:c==null?"":E(c),d=!1;a.forEach(l=>{let g=(l.getAttribute("data-r-match-when")??"")===u;l.hidden=!g,g&&(d=!0)}),i&&(i.hidden=d)};s(o.value),o.subscribe(s),G.add(n)})}function J(){let t=window.__resuma;if(!t)return;let e=document.getElementById("resuma-root")??document.body;w(e,t.signals),b(e,t.signals),x(e,t.signals),_(e,t.signals),H(e,t.signals)}var Ct="resuma-island";function S(t,e){t.querySelectorAll(Ct).forEach(r=>{let o=r.getAttribute("data-r-chunk");if(!o)return;if((r.getAttribute("data-r-load")??"eager")==="visible"&&"IntersectionObserver"in window){new IntersectionObserver((s,c)=>{for(let u of s)u.isIntersecting&&(c.unobserve(u.target),z(r,o,e))},{rootMargin:"100px"}).observe(r);return}z(r,o,e)})}async function z(t,e,n){let r=t.getAttribute("data-r-props")??"{}",o={};try{o=JSON.parse(r)}catch{}await At(e,o,t,n)}async function At(t,e,n,r){if(n.dataset.rHydrated!=="true")try{let o=await import(`/_resuma/island-chunk/${t}.js`);typeof o.resume=="function"&&(o.resume(e,r,n),n.dataset.rHydrated="true")}catch(o){console.debug("[resuma] island chunk unavailable, staying static",t,o)}}function xt(t,e,n){let r=Object.create(n.state);if(!t)return r;for(let[o,a]of Object.entries(t)){let i=e.get(h(a));i&&(r[o]=i)}return r}var L=[];function X(){for(;L.length;){let t=L.pop();try{t?.()}catch{}}}function Y(t,e,n){for(let r of t)try{let o=xt(r.captures,e,n),a=new Function(`return (${r.body});`)(),i=r.target!=null?e.get(h(r.target))??null:null,s=()=>{try{let l=a(o,n);i&&l!==void 0&&i.set(l)}catch(l){console.error("[resuma] effect",r.id,l)}},c,u=()=>{let l=r.debounce_ms;if(l!=null&&l>0){c!==void 0&&clearTimeout(c),c=setTimeout(s,l);return}s()};u(),L.push(()=>{c!==void 0&&clearTimeout(c)});let d=new Set;for(let l of r.deps)d.add(h(l));if(r.captures)for(let l of Object.values(r.captures))d.add(h(l));for(let l of d){let g=e.get(l)?.subscribe(()=>u());g&&L.push(g)}}catch(o){console.error("[resuma] effect init",r.id,o)}}function Q(t){let e=window.__resuma;e&&(e.loaded.has(t)||import(`/_resuma/handler/${t}.js`).then(n=>{e.loaded.set(t,n)}).catch(()=>{}))}function Z(t,e){let n=[...new Set(t.filter(o=>o&&o!=="__page__"))];if(!n.length)return;if(!("IntersectionObserver"in window)){for(let o of n)Q(o);return}let r=new IntersectionObserver((o,a)=>{for(let i of o){if(!i.isIntersecting)continue;let s=i.target.dataset.rChunk;s&&Q(s),a.unobserve(i.target)}},{rootMargin:"120px"});for(let o of e.querySelectorAll("resuma-boundary[data-r-chunk]"))r.observe(o);for(let o of n){let a=document.createElement("resuma-boundary");a.hidden=!0,a.dataset.rChunk=o,e.appendChild(a),r.observe(a)}}var tt=new Map,I=new Map;async function nt(t,e){if(e){let s=tt.get(e);return s||(s=et(e),tt.set(e,s)),s}let[n,r]=t.split("#"),o=window.__resuma;if(n==="__page__"){let s=o.handlers[n]?.[r];if(s)return et(s);throw new Error(`[resuma] inline handler ${r} not found in __page__ payload`)}let a=o.loaded.get(n);if(!a){let s=I.get(n);s||(s=import(`/_resuma/handler/${n}.js`),I.set(n,s),s.finally(()=>I.delete(n))),a=await s,o.loaded.set(n,a)}let i=a[r];if(!i)throw new Error(`[resuma] handler ${r} not found in chunk ${n}`);return i}function et(t){let e=t.trim(),r=e.startsWith("(")||e.startsWith("function")||e.startsWith("async")?`return (${t});`:`return (async (event, state, __resuma) => { ${t} });`;return new Function(r)()}var at="resuma-root",F="resuma-state",C=new Map,P=new Set;async function _t(t){if(!(!t||C.has(t)||P.has(t))&&!(t.startsWith("http")&&!t.startsWith(location.origin))){P.add(t);try{let e=await fetch(t,{headers:{Accept:"text/html"},credentials:"same-origin"});e.ok&&C.set(t,await e.text())}catch{}finally{P.delete(t)}}}var W=null;function it(t){W=t}function O(){return document.getElementById(at)??document.body}function Ht(t){try{return new URL(t,location.origin).origin===location.origin}catch{return!1}}function It(t){if(!t?.textContent)return{signals:[],handlers:{},islands:[],actions:[]};try{return JSON.parse(t.textContent)}catch(e){return console.error("[resuma] failed to parse state payload",e),{signals:[],handlers:{},islands:[],actions:[]}}}function Pt(t,e){if(t===e)return!0;let n="http://resuma.local",r=new URL(t,n),o=new URL(e,n);if(r.search)return r.pathname+r.search===o.pathname+o.search;if(r.pathname===o.pathname)return!0;if(r.pathname!=="/"&&o.pathname.startsWith(r.pathname)){let a=o.pathname.charCodeAt(r.pathname.length);return a===void 0||a===47}return!1}function rt(t){document.querySelectorAll("a[data-r-nav]").forEach(e=>{let n=e.getAttribute("href");if(!n)return;let r=e.getAttribute("data-r-active-class");if(!r)return;let o=(e.getAttribute("data-r-base-class")??e.className).split(/\s+/).filter(a=>a&&a!==r).join(" ");e.setAttribute("data-r-base-class",o),e.className=Pt(n,t)?`${o} ${r}`.trim():o})}function qt(){if(!window.__resuma){window.location.reload();return}if(W){W(),rt(location.pathname+location.search);return}let t=It(document.getElementById(F)),e=M(t.signals),n={};for(let[i,s]of e)n[i]=s;let r=window.__resuma,o={state:n,signals:e,handlers:t.handlers,contexts:t.contexts??{},loaded:r.loaded??new Map,action:r.action,safeAction:r.safeAction,refreshIsland:r.refreshIsland,context:i=>o.contexts[i],navigate:p,buildUrl:k,invalidate:N};window.__resuma=o;let a=O();w(a,e),b(a,e),S(a,e),rt(location.pathname+location.search)}function Ft(){let t=O(),e=t.querySelector("[autofocus]")??t.querySelector("h1, [role='heading'], main")??t;e.hasAttribute("tabindex")||e.setAttribute("tabindex","-1");try{e.focus({preventScroll:!0})}catch{e.focus()}}function k(t,e){let n=new URL(t,location.origin);if(e)for(let[r,o]of Object.entries(e))o!=null&&o!==""&&n.searchParams.set(r,o);return n.pathname+n.search}async function N(t,e){let n=t?.split("?")[0]??location.pathname,r=String(Date.now());await p(k(n,{...e,_r:r}))}var q=0,ot=null;async function p(t,e=!0){if(!Ht(t)){window.location.assign(t);return}let n=++q;ot?.abort();let r=new AbortController;ot=r;try{let o=C.get(t);if(o)C.delete(t);else{let u=await fetch(t,{headers:{Accept:"text/html"},credentials:"same-origin",signal:r.signal});if(n!==q)return;if(!u.ok){window.location.href=t;return}o=await u.text()}if(n!==q)return;let a=new DOMParser().parseFromString(o,"text/html"),i=a.getElementById(at),s=a.getElementById(F);if(!i||!s?.textContent){window.location.href=t;return}O().innerHTML=i.innerHTML;let c=document.getElementById(F);c&&(c.textContent=s.textContent),a.title&&(document.title=a.title),e&&history.pushState({resumaNav:!0},"",t),qt(),e&&window.scrollTo(0,0),Ft(),document.dispatchEvent(new CustomEvent("resuma:navigate",{detail:{href:t}}))}catch(o){if(o instanceof DOMException&&o.name==="AbortError")return;console.error("[resuma] navigation failed",o),window.location.href=t}}function $(t){if(t.startsWith("/")&&!t.startsWith("//")){p(t);return}try{let e=new URL(t,location.origin);if(e.origin===location.origin&&(e.protocol==="http:"||e.protocol==="https:")){p(e.pathname+e.search+e.hash);return}}catch{}console.warn("[resuma] ignored unsafe redirect target",t)}function Wt(t,e){if(e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||t.target&&t.target!=="_self")return!1;let n=t.getAttribute("href");if(!n||n.startsWith("#")||n.startsWith("javascript:"))return!1;if(n.startsWith("http://")||n.startsWith("https://"))try{return new URL(n).origin===location.origin}catch{return!1}return!0}function st(){document.addEventListener("mouseenter",t=>{let e=t.target;if(!(e instanceof Element))return;let r=e.closest("a[data-r-nav]")?.getAttribute("href");r&&_t(r)},!0),document.addEventListener("click",t=>{let e=t.target;if(!(e instanceof Element))return;let n=e.closest("a[data-r-nav]");if(!n||!Wt(n,t))return;let r=n.getAttribute("href");r&&(t.preventDefault(),p(r))}),window.addEventListener("popstate",()=>{p(location.pathname+location.search,!1)})}var ct="[data-r-flow-dashboard], [data-r-flow-graph], [data-r-event-stream], [data-r-worker-panel]";function Ot(t){return t instanceof Document||t instanceof Element?!!t.querySelector(ct):!1}async function dt(t){if(Ot(t))try{(await import("/_resuma/flow.js")).initFlowWidgets(t)}catch(e){console.error("[resuma] flow widgets failed to load",e)}}function ge(t=document){dt(t)}var ft="resuma-state",Nt="resuma-root";function $t(){let t=document.getElementById(ft);if(!t?.textContent)return"";try{return JSON.parse(t.textContent).csrf_token??""}catch{return""}}function gt(t={}){let e={...t},n=$t();return n&&(e["x-resuma-csrf"]=n),e}var A=()=>document.getElementById(Nt)??document.body;function Dt(){let t=document.getElementById(ft);if(!t||!t.textContent)return{signals:[],handlers:{},islands:[],actions:[]};try{return JSON.parse(t.textContent)}catch(e){return console.error("[resuma] failed to parse state payload",e),{signals:[],handlers:{},islands:[],actions:[]}}}var lt=!1;function ut(){X();let t=Dt(),e=M(t.signals),n={};for(let[i,s]of e)n[i]=s;let r=window.__resuma,o={state:n,signals:e,handlers:t.handlers,contexts:t.contexts??{},loaded:r?.loaded??new Map,action:pt,safeAction:Xt,refreshIsland:ht,context:i=>o.contexts[i],navigate:p,buildUrl:k,invalidate:N};window.__resuma=o;let a=A();w(a,e),b(a,e),x(a,e),_(a,e),H(a,e),S(a,e),Vt(a),Kt(a),Jt(a),dt(a),zt(t.visible_tasks??{},n),Y(t.effects??[],e,o),Z(t.lazy_chunks??[],a)}async function me(){lt||(lt=!0,it(ut),ut(),Bt(),Gt(),st(),Yt())}function jt(t){let e=window.__resuma;if(!t.length)return e.state;let n={};for(let r of t){let o=r.indexOf(":"),a=o===-1?r:r.slice(0,o),s=(o===-1?void 0:r.slice(o+1))??a,c=e.signals.get(s);c&&(n[a]=c)}return Object.assign(Object.create(e.state),n)}async function pe(t,e,n,r){let o=await nt(t,e),a=jt(r);await o(n,a,window.__resuma)}function Bt(){document.addEventListener("submit",async t=>{if(!(t.target instanceof HTMLFormElement))return;let e=t.target;if(!e.getAttribute("data-r-submit"))return;t.preventDefault();let n=e.getAttribute("data-r-submit"),r=new FormData(e),o={};r.forEach((i,s)=>{o[s]=String(i)});let a=new URLSearchParams(o);try{let i=await fetch(e.action||`/_resuma/submit/${encodeURIComponent(n)}`,{method:"POST",credentials:"same-origin",headers:gt({"content-type":"application/x-www-form-urlencoded",accept:"application/json"}),body:a.toString()}),s=await i.json();if(!i.ok||s.ok===!1){Ut(e,s.field_errors??{}),(i.status>=500||!s.field_errors)&&console.error("[resuma] submit error",s.error??`submit ${n} failed`);return}mt(e),s.redirect&&$(s.redirect)}catch(i){console.error("[resuma] submit error",i)}},!0)}function Ut(t,e){mt(t);for(let[n,r]of Object.entries(e)){let o=t.querySelector(`[name="${CSS.escape(n)}"]`);if(!o)continue;let a=document.createElement("span");a.className="resuma-field-error",a.setAttribute("data-r-field-error",n),a.textContent=r,o.insertAdjacentElement("afterend",a)}}function mt(t){t.querySelectorAll("[data-r-field-error]").forEach(e=>e.remove())}function Gt(){document.addEventListener("submit",t=>{if(!(t.target instanceof HTMLFormElement))return;let e=t.target;if(!e.hasAttribute("data-r-loader-refresh")||e.getAttribute("data-r-on:submit")||e.querySelector("[data-r-on\\:submit]"))return;t.preventDefault();let n=new FormData(e),r={};n.forEach((a,i)=>{let s=String(a);s&&(r[i]=s)});let o=e.getAttribute("action")||location.pathname;window.__resuma?.navigate(k(o,r))},!0)}function Vt(t){t.querySelectorAll("template[data-r-stream-chunk]").forEach(e=>{let n=e.getAttribute("data-r-stream-chunk");if(!n)return;let r=t.querySelector(`template[data-r-stream="${n}"]`);if(!r||!r.parentElement)return;let o=e.innerHTML,a=document.createRange().createContextualFragment(o);r.replaceWith(a),e.remove()})}function Kt(t){t.querySelectorAll("template[data-r-portal]").forEach(e=>{let n=e.closest("[data-r-show-if]");if(n?.closest("resuma-show")?.dataset.rPortalTarget||n?.hidden)return;let r=e.getAttribute("data-r-portal");if(!r)return;let o=document.getElementById(r)??document.querySelector(`[data-r-portal-target="${r}"]`);o&&o.replaceChildren(e.content.cloneNode(!0))})}function Jt(t){"startViewTransition"in document&&t.querySelectorAll("[data-r-vt]").forEach(e=>{e.addEventListener("click",n=>{let r=n.target?.closest("a[href]");if(!r||r.getAttribute("target")==="_blank")return;let o=r.getAttribute("href");if(!o||o.startsWith("#")||o.startsWith("javascript:"))return;n.preventDefault();let a=()=>{window.location.href=o};document.startViewTransition?.(a)})})}function zt(t,e){let n=Object.entries(t);if(!n.length)return;let r=(i,s)=>{try{let c=s.trim();c.endsWith(")()")&&(c=c.slice(0,-2));let u=new Function("state","__resuma",`return (${c})(state, __resuma);`);Promise.resolve(u(e,window.__resuma))}catch(c){console.error("[resuma] visible task",i,c)}},o=new Set(n.map(([i])=>i)),a=(i,s)=>{o.has(i)&&(o.delete(i),r(i,s))};for(let[i,s]of n)a(i,s);if("IntersectionObserver"in window){let i=new IntersectionObserver((s,c)=>{for(let u of s){if(!u.isIntersecting)continue;let d=u.target.dataset.rVisibleTask,l=d?t[d]:void 0;d&&l&&a(d,l),c.unobserve(u.target)}},{rootMargin:"50px"});A().querySelectorAll("[data-r-visible-task]").forEach(s=>s.remove());for(let[s]of n){let c=document.createElement("span");c.dataset.rVisibleTask=s,c.style.cssText="position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden",A().appendChild(c),i.observe(c)}}}async function pt(t,e){let n=await fetch(`/_resuma/action/${encodeURIComponent(t)}`,{method:"POST",credentials:"same-origin",headers:gt({"content-type":"application/json"}),body:JSON.stringify({args:e})});if(!n.ok)throw new Error(`[resuma] action ${t} failed: ${n.status}`);let r=await n.json();if(r.ok===!1)throw new Error(r.error??"action failed");return r.redirect&&$(r.redirect),r.value}async function Xt(t,e){try{return{ok:!0,value:await pt(t,e)}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}}async function ht(t){let e=await fetch(`/_resuma/island/${encodeURIComponent(t)}`);if(!e.ok)return;let n=await e.text(),r=document.querySelector(`resuma-island[data-r-instance="${t}"]`);r&&(r.outerHTML=n),J();let o=window.__resuma?.signals;o&&S(A(),o)}function Yt(){if(!window.__resumaDev||typeof WebSocket>"u")return;let t=location.protocol==="https:"?"wss":"ws",e=!1,n=()=>{let r=new WebSocket(`${t}://${location.host}/_resuma/dev/ws`);r.addEventListener("open",()=>{if(e){location.reload();return}e=!0}),r.addEventListener("message",o=>{let a=String(o.data);if(a==="reload"){location.reload();return}a.startsWith("island:")&&ht(a.slice(7))}),r.addEventListener("close",()=>{setTimeout(n,500)}),r.addEventListener("error",()=>{r.close()})};n()}export{me as bootstrap,jt as buildLocalState,ge as mountFlowWidgets,ut as mountPage,gt as mutationHeaders,pe as runHandler};