what-server 0.13.3 → 0.13.5

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/index.min.js CHANGED
@@ -1,6 +1,6 @@
1
- import{h as et,_isAriaAttr as ue,_beginComponentSSR as nt,_endComponentSSR as rt,_mapArrayToArray as ot,getServerContext as Tt,runWithServerContext as S,beginHeadCollection as de,endHeadCollection as at}from"what-core";var $t=new RegExp("[<>&\\u2028\\u2029]","g"),Pt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function V(t){return JSON.stringify(t).replace($t,e=>Pt[e.charCodeAt(0)])}import{mount as ke,hydrate as Ce,signal as Oe,batch as $e,getServerContext as xt}from"what-core";var vt=new Map;function It(t){let e=t||xt();return e&&e.islandStores instanceof Map?e.islandStores:null}function ht(t){let e=typeof document<"u"?vt:It(t),n={};for(let[r,s]of e||[])n[r]=s._getSnapshot();return n}import{signal as _,batch as G}from"what-core";var D=Symbol.for("what.revalidationHandler"),yt=!(typeof process<"u");function W(t){globalThis[D]=t}function Nt(){return globalThis[D]??null}async function z(t,e){let n=globalThis[D];if(n&&n.revalidatePath)return n.revalidatePath(t,e);yt&&console.warn(`[what] revalidatePath('${t}') had no effect: no cache engine is bound. Create a what-isr engine and bind it in your adapter (setRevalidationHandler).`)}async function Y(t,e){let n=globalThis[D];if(n&&n.revalidateTag)return n.revalidateTag(t,e);yt&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var X=new Map;function Dt(){if(typeof document<"u"){let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);if(e)return decodeURIComponent(e[1])}return null}function K(){if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let t=new Uint8Array(16);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}throw Object.assign(new Error("[what] No secure random source available for CSRF token generation"),{code:"ERR_NO_SECURE_RANDOM"})}function mt(t,e){if(!t||!e||t.length!==e.length)return!1;let n=0;for(let r=0;r<t.length;r++)n|=t.charCodeAt(r)^e.charCodeAt(r);return n===0}function Z(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}">`}var Ht=0,Lt=!1;function jt(){return!Lt&&typeof process<"u",`a_${typeof crypto<"u"&&crypto.getRandomValues?Array.from(crypto.getRandomValues(new Uint8Array(6)),e=>e.toString(16).padStart(2,"0")).join(""):`c${(++Ht).toString(36)}_${Date.now().toString(36)}`}`}function Mt(t,e={}){let n=e.id||jt(),{onError:r,onSuccess:s,revalidate:a}=e;typeof window>"u"&&X.set(n,{fn:t,options:e});async function o(...i){if(typeof window>"u")return t(...i);let c=e.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let f=Dt(),l={"Content-Type":"application/json","X-What-Action":n};f&&(l["X-CSRF-Token"]=f);let p=await fetch("/__what_action",{method:"POST",headers:l,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let w=await p.json().catch(()=>({message:"Action failed"}));throw Object.assign(new Error(w.message||"Action failed"),{code:"ERR_ACTION_FAILED"})}let h=await p.json();if(s&&s(h),a)for(let w of a)St(w);return h}catch(f){if(f.name==="AbortError"){let l=new Error(`Action "${n}" timed out after ${c}ms`);throw l.code="TIMEOUT",r&&r(l),l}throw r&&r(f),f}finally{clearTimeout(d)}}return o._actionId=n,o._isAction=!0,o}function gt(t,e={}){let{onSuccess:n,onError:r,resetOnSuccess:s=!0}=e;return async a=>{let o,i;a instanceof Event?(a.preventDefault(),i=a.target,o=new FormData(i)):o=a;let c={},u=!1;for(let[d,f]of o.entries())typeof File<"u"&&f instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(f):c[d]=[c[d],f]:c[d]=f;try{let d=u?await t(c,o):await t(c);return n&&n(d,i),s&&i&&i.reset(),d}catch(d){throw r&&r(d,i),d}}}function wt(t){let e=_(!1),n=_(null),r=_(null);async function s(...a){e.set(!0),n.set(null);try{let o=await t(...a);return r.set(o),o}catch(o){throw n.set(o),o}finally{e.set(!1)}}return{trigger:s,isPending:()=>e(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Ft(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},s=wt(gt(t,{resetOnSuccess:n}));function a(o){o.preventDefault();let i=new FormData(o.target);return r.current=o.target,s.trigger(i)}return{...s,handleSubmit:a,formRef:r}}function Ut(t,e){let n=_(t),r=_([]),s=_(t);function a(u){let d=e(n.peek(),u);G(()=>{r.set([...r.peek(),u]),n.set(d)})}function o(u,d){G(()=>{if(r.set(r.peek().filter(f=>f!==u)),d!==void 0){s.set(d);let f=d;for(let l of r.peek())f=e(f,l);n.set(f)}})}function i(u,d){G(()=>{let f=r.peek().filter(h=>h!==u);r.set(f);let l=d!==void 0?d:s.peek();s.set(l);let p=l;for(let h of f)p=e(p,h);n.set(p)})}async function c(u,d){a(u);try{let f=await d();return o(u,f),f}catch(f){throw i(u),f}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:a,resolve:o,rollback:i,withOptimistic:c,set:u=>{n.set(u),s.set(u)}}}var v=new Map;function Bt(t,e){return v.has(t)||v.set(t,new Set),v.get(t).add(e),()=>{v.get(t)?.delete(e)}}function St(t){let e=v.get(t);if(e)for(let n of e)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function H(t,e,n,r={}){let{csrfToken:s,skipCsrf:a=!1}=r;if(!a){if(!s)return Promise.resolve({status:500,body:{message:"[what] CSRF token not configured. Pass { csrfToken: sessionToken } to handleActionRequest, or { skipCsrf: true } to explicitly opt out."}});let i=t?.headers?.["x-csrf-token"]||t?.headers?.["X-CSRF-Token"];if(!mt(i,s))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let o=X.get(e);return o?Array.isArray(n)?o.fn(...n).then(async i=>{let c=o.options||{};if(Array.isArray(c.revalidate))for(let u of c.revalidate)await z(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await Y(u);return{status:200,body:i}}).catch(i=>(console.error(`[what] Action "${e}" error:`,i),{status:500,body:{message:"Action failed"}})):Promise.resolve({status:400,body:{message:"Invalid action arguments"}}):Promise.resolve({status:404,body:{message:"Action not found"}})}function Jt(){return[...X.keys()]}function Vt(t,e={}){let{onSuccess:n,onError:r,onSettled:s}=e,a={isPending:_(!1),error:_(null),data:_(null)};async function o(...i){a.isPending.set(!0),a.error.set(null);try{let c=await t(...i);return a.data.set(c),n&&n(c,...i),c}catch(c){throw a.error.set(c),r&&r(c,...i),c}finally{a.isPending.set(!1),s&&s(a.data.peek(),a.error.peek(),...i)}}return{mutate:o,isPending:()=>a.isPending(),error:()=>a.error(),data:()=>a.data(),reset:()=>{a.error.set(null),a.data.set(null)}}}import{h as L}from"what-core";var bt="/__what_action";function Wt(t){if(typeof t=="string")return t;if(typeof t=="function"){let e=t._actionId;if(e)return e;throw Object.assign(new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string."),{code:"ERR_FORM_ACTION_NOT_REGISTERED"})}throw Object.assign(new Error("[what] <Form> requires an `action` prop: a server action or its id."),{code:"ERR_FORM_ACTION_MISSING"})}function zt(){if(typeof document>"u")return null;let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return e?decodeURIComponent(e[1]):null}function Yt({action:t,csrfToken:e,redirect:n,method:r="post",enhance:s=!0,children:a,...o}){let i=Wt(t),c=e!==void 0?e:zt();c==null&&typeof process<"u";let u=[L("input",{type:"hidden",name:"_action",value:i}),L("input",{type:"hidden",name:"what-csrf-token",value:c||""})];n&&u.push(L("input",{type:"hidden",name:"_redirect",value:n}));let d={...o,method:r,action:o.action||bt,"data-action":i};s&&(d["data-enhance"]="");let f=a==null?[]:Array.isArray(a)?a:[a];return L("form",d,...u,...f)}var Gt="/__what_action",Rt=1024*1024;function Xt(t){if(!t)return{};if(typeof t.forEach=="function"&&typeof t.get=="function"){let n={};return t.forEach((r,s)=>{n[s.toLowerCase()]=r}),n}let e={};for(let n in t)e[n.toLowerCase()]=t[n];return e}function j(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function Q(t,e){return{status:t,headers:{"content-type":"text/html; charset=utf-8"},body:`<!DOCTYPE html><html><body><h1>${t}</h1><p>${String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</p></body></html>`}}function _t(t){if(typeof t!="string"||!t.startsWith("/")||/^[/\\]{2}/.test(t)||t.includes("\\"))return null;try{let e=new URL(t,"http://localhost");return e.origin!=="http://localhost"?null:e.pathname+e.search}catch{return null}}function Kt(t,e){let n=_t(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let s=new URL(r,"http://localhost"),a=_t(s.pathname+s.search);if(a)return a}catch{}return"/"}var Zt=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function I(t={}){let{getCsrfToken:e,skipCsrf:n=!1}=t;return async function(s){if((s.method||"POST").toUpperCase()!=="POST")return j(405,{message:"Method Not Allowed"});let o=Xt(s.headers),i=o["x-what-action"],c=o["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=n?void 0:e?await e(s):void 0;if(u){let h=s.body||{},w=h._action||h["data-action"]||s.query&&s.query.action;if(!w)return Q(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let b={...o},k=h._csrf??h["what-csrf-token"];if(k&&!b["x-csrf-token"]&&(b["x-csrf-token"]=String(k)),!n&&e&&!d)return Q(403,"Missing CSRF token");let C={};for(let[O,U]of Object.entries(h))Zt.has(O)||(C[O]=U);let T=await H({headers:b},w,[C],{csrfToken:d,skipCsrf:n});return T.status===200?{status:303,headers:{location:Kt(h,o)},body:""}:Q(T.status,T.body&&T.body.message||"Action failed")}if(!i)return j(400,{message:"Missing X-What-Action header"});if(!n&&e&&!d)return j(403,{message:"Missing CSRF token"});let l=(s.body||{}).args,p=await H({headers:o},i,l,{csrfToken:d,skipCsrf:n});return j(p.status,p.body)}}function Qt(t={}){let e=t.basePath||Gt,n=I(t);return async function(s,a,o){let[i,c]=(s.url||"").split("?");if(i!==e||(s.method||"").toUpperCase()!=="POST")return o?o():void 0;let u;try{let l=await qt(s);u=M(l,s.headers["content-type"]||"")}catch(l){a.writeHead(l.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),a.end(JSON.stringify({message:l.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let d=Object.fromEntries(new URLSearchParams(c||"")),f=await n({method:s.method,headers:s.headers,body:u,query:d});a.writeHead(f.status,f.headers),a.end(f.body)}}function M(t,e){if((e||"").includes("application/x-www-form-urlencoded")){let n={};for(let[r,s]of new URLSearchParams(String(t)))n[r]===void 0?n[r]=s:Array.isArray(n[r])?n[r].push(s):n[r]=[n[r],s];return n}return t==null||t===""?{}:JSON.parse(String(t))}async function F(t,e=Rt){let n=Number(t.headers.get("content-length"));if(Number.isFinite(n)&&n>e)return{tooLarge:!0};let r=t.body;if(!r||typeof r.getReader!="function"){let i=await t.text();return Buffer.byteLength(i,"utf8")>e?{tooLarge:!0}:{raw:i}}let s=r.getReader(),a=[],o=0;for(;;){let{done:i,value:c}=await s.read();if(i)break;if(c){if(o+=c.byteLength,o>e){try{await s.cancel()}catch{}return{tooLarge:!0}}a.push(c)}}return{raw:Buffer.concat(a.map(i=>Buffer.from(i))).toString("utf8")}}function qt(t){return new Promise((e,n)=>{let r=0,s=[];t.on("data",a=>{if(r+=a.length,r>Rt){let o=new Error("Body too large");o.code="BODY_TOO_LARGE",n(o),t.destroy?.();return}s.push(a)}),t.on("end",()=>{if(s.length===0)return e("");e(Buffer.concat(s).toString("utf8"))}),t.on("error",n)})}function te(t={}){let e=I(t);return async function(n){let r={};try{let o=await F(n);if(o.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=M(o.raw,n.headers.get("content-type")||"")}catch{r={}}let s={};try{s=Object.fromEntries(new URL(n.url,"http://localhost").searchParams)}catch{}let a=await e({method:n.method,headers:n.headers,body:r,query:s});return new Response(a.body,{status:a.status,headers:a.headers})}}import{matchRoute as ee,parseQuery as ne}from"what-router/match";var re="/__what_action",oe="/__what_revalidate",q="what-csrf";function N(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((n,r)=>{e[r.toLowerCase()]=n}),e}function At(t,e){if(!t)return null;let n=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function ae(t){try{let e=await F(t);return e.tooLarge?{tooLarge:!0}:M(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function se(t){let e;try{e=await F(t)}catch{return{json:{}}}if(e.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(e.raw??"")}}catch{return{json:{}}}}function ie(t){return async function(n){let{route:r,params:s,query:a,request:o,csrfToken:i}=n,c={default:r.component,loader:r.loader},u=i?{params:s,query:a,request:o,csrfToken:i}:{params:s,query:a,request:o},d=i?{...t,csrfToken:i}:t;return{html:await Et(c,u,d),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function tt(t={}){let{routes:e=[],cache:n,render:r,revalidateWebhook:s,document:a={},notFound:o,basePath:i="",csrf:c=!0}=t,u=c!==!1&&!t.actionHandler,d=t.actionHandler||I(u?{getCsrfToken:l=>At(l.headers&&l.headers.cookie,q)}:{skipCsrf:!0}),f=r||ie(a);return n&&(n.revalidatePath||n.revalidateTag)&&W({revalidatePath:n.revalidatePath,revalidateTag:n.revalidateTag}),async function(p){let h=new URL(p.url,"http://localhost"),w=h.pathname;if(i&&w.startsWith(i)&&(w=w.slice(i.length)||"/"),p.method==="POST"&&w===re){let m=await ae(p);if(m&&m.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await d({method:"POST",headers:N(p.headers),body:m,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let b=null,k=null;if(u&&(b=At(N(p.headers).cookie,q),!b)){b=K();let A=N(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;k=`${q}=${encodeURIComponent(b)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let C=m=>(k&&(m["set-cookie"]=k),m);if(p.method==="POST"&&w===oe&&s){let m=await se(p);if(m.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await s({headers:N(p.headers),body:m.json});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let T=ee(w,e);if(!T){let m=o?o():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(m,{status:404,headers:C({"content-type":"text/html; charset=utf-8"})})}let{route:O,params:U}=T,B=O.page||{mode:O.mode||"client"},x={path:w,query:ne(h.search),config:B,route:O,params:U,request:p};if(n&&B.mode!=="server"){x.varyHeaders=N(p.headers);let m=await n.handle(x,()=>f(x));return new Response(m.html,{status:m.status||200,headers:C({"content-type":"text/html; charset=utf-8",...m.headers||{}})})}b&&(x.csrfToken=b);let J=await f(x),pt=C({"content-type":"text/html; charset=utf-8",...J.headers||{}});return B.mode==="server"&&(pt["Cache-Control"]="private, no-store"),new Response(J.html,{status:J.status||200,headers:pt})}}function ce(t={}){let e=tt(t);return{async fetch(n,r,s){return r&&(n.__env=r),s&&(n.__ctx=s),e(n)}}}function E(t){return{head:de(),loaderData:t,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var kt=0;function fe(){kt=0}function le(){return"h"+kt++}function pe(t){if(!Tt()){let e=E(void 0);return S(e,()=>pe(t))}return fe(),R(t)}var Ct=new Set(["__errorBoundary","__suspense"]),st=new Set(["__portal"]);function it(t){let e=t.children;return!e||e.length===0?{...t.props}:{...t.props,children:e}}function ct(t,e){let n=t.props&&t.props.fallback;if(typeof n!="function")return n;let r=t.props&&t.props.reset||(()=>{});try{return n({error:e,reset:r})}catch(s){return P&&console.warn(`[what-server] <ErrorBoundary> fallback threw during SSR: ${s.message}`),null}}function R(t){if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return g(String(t));if(typeof t=="function"&&t._signal)return`<!--$-->${R(t())}<!--/$-->`;if(typeof t=="function"&&t._mapArray)try{return`<!--$-->${R(ot(t))}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(typeof t=="function")try{return`<!--$-->${R(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(R).join("")}<!--/[]-->`;if(st.has(t.tag))return"";if(Ct.has(t.tag))try{return(t.children||[]).map(R).join("")}catch(c){let u=c&&typeof c.then=="function";if(u&&t.tag==="__errorBoundary"||!u&&t.tag==="__suspense")throw c;return R(ct(t,u?null:c))}if(typeof t.tag=="function"){let c=le(),u=nt(t.tag),d;try{d=R(t.tag(it(t)))}finally{rt(u)}return he(d,c)}let{tag:e,props:n,children:r}=t;dt(e);let s=ft(n||{}),a=`<${e}${s}>`;if(lt.has(e))return a;let o=ut(n),i=o!=null?String(o):r.map(R).join("");return`${a}${i}</${e}>`}function he(t,e){let n=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],s=n[2],a=r.length+1+s.length,o=t.indexOf(">",a),i=t.slice(a,o===-1?void 0:o);return/[\s"']data-hk\s*=/.test(i)||/^\s*data-hk\s*=/.test(i)?t:t.slice(0,a)+` data-hk="${e}"`+t.slice(a)}return t}function y(t){if(!Tt()){let c=E(void 0);return S(c,()=>y(t))}if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return g(String(t));if(typeof t=="function"&&t._signal)return y(t());if(typeof t=="function"&&t._mapArray)try{return y(ot(t))}catch{return typeof process<"u",""}if(typeof t=="function")try{return y(t())}catch{return typeof process<"u",""}if(Array.isArray(t))return t.map(y).join("");if(st.has(t.tag))return"";if(Ct.has(t.tag))try{return(t.children||[]).map(y).join("")}catch(c){let u=c&&typeof c.then=="function";if(u&&t.tag==="__errorBoundary"||!u&&t.tag==="__suspense")throw c;return y(ct(t,u?null:c))}if(typeof t.tag=="function"){let c=nt(t.tag);try{return y(t.tag(it(t)))}finally{rt(c)}}let{tag:e,props:n,children:r}=t;dt(e);let s=ft(n||{}),a=`<${e}${s}>`;if(lt.has(e))return a;let o=ut(n),i=o!=null?String(o):r.map(y).join("");return`${a}${i}</${e}>`}function Ze(t){let e=E(void 0);return{body:S(e,()=>y(t)),head:at(e.head)}}async function Qe(t,e={}){let n=t.default||t,r=typeof t.loader=="function"?await t.loader(e):void 0,s=E(r),a=e.params||{};return{body:S(s,()=>y(et(n,{...a,loaderData:r}))),head:at(s.head),loaderData:r}}var Ot=12;async function ye(t,e){e||(e=E(void 0));let n="";for(let s=0;s<Ot;s++){n=S(e,()=>y(t));let a=[...e.resources.values()].filter(o=>o.status==="pending").map(o=>o.promise);if(a.length===0)break;await Promise.all(a)}let r={};for(let[s,a]of e.resources)a.status==="ready"&&(r[s]=a.value);return{body:n,head:at(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function Et(t,e={},n={}){let r=t.default||t,s=typeof t.loader=="function"?await t.loader(e):void 0,a=E(s),o=e.params||{},{body:i,head:c,resources:u}=await ye(et(r,{...o,loaderData:s}),a),d={loaderData:s??null,resources:u,islandStores:ht(a)};return me({body:i,head:c,payload:d,options:n})}function me({body:t,head:e,payload:n,options:r={}}){let s=r.lang||"en",a=`<script id="__what_data" type="application/json">${V(n)}<\/script>`,o=r.clientEntry?`<script type="module" src="${g(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?Z(r.csrfToken):"")+(r.head||""),u=r.bodyClass?` class="${g(r.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${g(s)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${e||""}${c}</head><body${u}>${t}${a}${o}</body></html>`}async function*$(t,e){if(e===void 0&&(e=E(void 0)),t==null||t===!1||t===!0)return;if(typeof t=="string"||typeof t=="number"){yield g(String(t));return}if(typeof t=="function"&&t._signal){let o=S(e,()=>t());yield*$(o,e);return}if(typeof t=="function"&&t._mapArray){let o=null;try{o=S(e,()=>ot(t))}catch{typeof process<"u"}o&&(yield*$(o,e));return}if(typeof t=="function"){try{let o=S(e,()=>t());yield*$(o,e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let o of t)yield*$(o,e);return}if(st.has(t.tag))return;if(t.tag==="__errorBoundary"){let o;try{o=S(e,()=>(t.children||[]).map(y).join(""))}catch(i){if(i&&typeof i.then=="function")throw i;o=S(e,()=>y(ct(t,i)))}yield o;return}if(t.tag==="__suspense"){let o=null;for(let i=0;i<Ot&&o===null;i++){let c=null;try{o=S(e,()=>(t.children||[]).map(y).join(""))}catch(u){if(u&&typeof u.then=="function")c=u;else throw u}if(o===null){let u=[...e.resources.values()].filter(d=>d.status==="pending").map(d=>d.promise);await Promise.all([c,...u].filter(Boolean))}}o===null&&(o=S(e,()=>y(t.props&&t.props.fallback))),yield o;return}if(typeof t.tag=="function"){let o=nt(t.tag);try{let i=S(e,()=>t.tag(it(t))),c=i instanceof Promise?await i:i;yield*$(c,e)}catch(i){typeof process<"u",yield P?`<!-- SSR Error: ${g(i.message||"Component error")} -->`:"<!-- SSR Error -->"}finally{rt(o)}return}let{tag:n,props:r,children:s}=t;dt(n);let a=ft(r||{});if(yield`<${n}${a}>`,!lt.has(n)){let o=ut(r);if(o!=null)yield String(o);else for(let i of s)yield*$(i,e);yield`</${n}>`}}function qe(t){return{mode:"static",...t}}function tn(t,e={}){let n=E(e),r=S(n,()=>y(et(t.component,e))),s=t.islands||[];return ge({title:t.title||"",meta:t.meta||{},body:r,islands:s,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function ge({title:t,meta:e,body:n,islands:r,scripts:s,styles:a,mode:o}){let i=Object.entries(e).map(([l,p])=>`<meta name="${g(l)}" content="${g(p)}">`).join(`
1
+ import{h as re,_isAriaAttr as dt,_beginComponentSSR as ne,_endComponentSSR as oe,_mapArrayToArray as ae,getServerContext as ke,runWithServerContext as S,beginHeadCollection as ft,endHeadCollection as se}from"what-core";var Pe=new RegExp("[<>&\\u2028\\u2029]","g"),Ie={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function W(e){return JSON.stringify(e).replace(Pe,t=>Ie[t.charCodeAt(0)])}import{mount as Ot,hydrate as $t,signal as Pt,batch as It,getServerContext as ve}from"what-core";var xe=new Map;function Ne(e){let t=e||ve();return t&&t.islandStores instanceof Map?t.islandStores:null}function ye(e){let t=typeof document<"u"?xe:Ne(e),r={};for(let[n,s]of t||[])r[n]=s._getSnapshot();return r}import{signal as R,batch as G}from"what-core";var H=Symbol.for("what.revalidationHandler"),me=!(typeof process<"u");function z(e){globalThis[H]=e}function De(){return globalThis[H]??null}async function X(e,t){let r=globalThis[H];if(r&&r.revalidatePath)return r.revalidatePath(e,t);me&&console.warn(`[what] revalidatePath('${e}') had no effect: no cache engine is bound. Create a what-isr engine and bind it in your adapter (setRevalidationHandler).`)}async function Y(e,t){let r=globalThis[H];if(r&&r.revalidateTag)return r.revalidateTag(e,t);me&&console.warn(`[what] revalidateTag('${e}') had no effect: no cache engine is bound.`)}var K=new Map;function He(){if(typeof document<"u"){let e=document.querySelector('meta[name="what-csrf-token"]');if(e)return e.getAttribute("content");let t=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);if(t)return decodeURIComponent(t[1])}return null}function Z(){if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let e=new Uint8Array(16);return crypto.getRandomValues(e),Array.from(e,t=>t.toString(16).padStart(2,"0")).join("")}throw Object.assign(new Error("[what] No secure random source available for CSRF token generation"),{code:"ERR_NO_SECURE_RANDOM"})}function ge(e,t){if(!e||!t||e.length!==t.length)return!1;let r=0;for(let n=0;n<e.length;n++)r|=e.charCodeAt(n)^t.charCodeAt(n);return r===0}function Q(e){return`<meta name="what-csrf-token" content="${String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}">`}var je=0,Le=!1;function Me(){return!Le&&typeof process<"u",`a_${typeof crypto<"u"&&crypto.getRandomValues?Array.from(crypto.getRandomValues(new Uint8Array(6)),t=>t.toString(16).padStart(2,"0")).join(""):`c${(++je).toString(36)}_${Date.now().toString(36)}`}`}function Fe(e,t={}){let r=t.id||Me(),{onError:n,onSuccess:s,revalidate:a}=t;typeof window>"u"&&K.set(r,{fn:e,options:t});async function o(...i){if(typeof window>"u")return e(...i);let c=t.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let f=He(),l={"Content-Type":"application/json","X-What-Action":r};f&&(l["X-CSRF-Token"]=f);let p=await fetch("/__what_action",{method:"POST",headers:l,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let w=await p.json().catch(()=>({message:"Action failed"}));throw Object.assign(new Error(w.message||"Action failed"),{code:"ERR_ACTION_FAILED"})}let h=await p.json();if(s&&s(h),a)for(let w of a)be(w);return h}catch(f){if(f.name==="AbortError"){let l=new Error(`Action "${r}" timed out after ${c}ms`);throw l.code="TIMEOUT",n&&n(l),l}throw n&&n(f),f}finally{clearTimeout(d)}}return o._actionId=r,o._isAction=!0,o}function we(e,t={}){let{onSuccess:r,onError:n,resetOnSuccess:s=!0}=t;return async a=>{let o,i;a instanceof Event?(a.preventDefault(),i=a.target,o=new FormData(i)):o=a;let c={},u=!1;for(let[d,f]of o.entries())typeof File<"u"&&f instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(f):c[d]=[c[d],f]:c[d]=f;try{let d=u?await e(c,o):await e(c);return r&&r(d,i),s&&i&&i.reset(),d}catch(d){throw n&&n(d,i),d}}}function Se(e){let t=R(!1),r=R(null),n=R(null);async function s(...a){t.set(!0),r.set(null);try{let o=await e(...a);return n.set(o),o}catch(o){throw r.set(o),o}finally{t.set(!1)}}return{trigger:s,isPending:()=>t(),error:()=>r(),data:()=>n(),reset:()=>{r.set(null),n.set(null)}}}function Ue(e,t={}){let{resetOnSuccess:r=!0}=t,n={current:null},s=Se(we(e,{resetOnSuccess:r}));function a(o){o.preventDefault();let i=new FormData(o.target);return n.current=o.target,s.trigger(i)}return{...s,handleSubmit:a,formRef:n}}function Be(e,t){let r=R(e),n=R([]),s=R(e);function a(u){let d=t(r.peek(),u);G(()=>{n.set([...n.peek(),u]),r.set(d)})}function o(u,d){G(()=>{if(n.set(n.peek().filter(f=>f!==u)),d!==void 0){s.set(d);let f=d;for(let l of n.peek())f=t(f,l);r.set(f)}})}function i(u,d){G(()=>{let f=n.peek().filter(h=>h!==u);n.set(f);let l=d!==void 0?d:s.peek();s.set(l);let p=l;for(let h of f)p=t(p,h);r.set(p)})}async function c(u,d){a(u);try{let f=await d();return o(u,f),f}catch(f){throw i(u),f}}return{value:()=>r(),isPending:()=>n().length>0,addOptimistic:a,resolve:o,rollback:i,withOptimistic:c,set:u=>{r.set(u),s.set(u)}}}var x=new Map;function Je(e,t){return x.has(e)||x.set(e,new Set),x.get(e).add(t),()=>{x.get(e)?.delete(t)}}function be(e){let t=x.get(e);if(t)for(let r of t)try{r()}catch(n){console.error("[what] Revalidation error:",n)}}function j(e,t,r,n={}){let{csrfToken:s,skipCsrf:a=!1}=n;if(!a){if(!s)return Promise.resolve({status:500,body:{message:"[what] CSRF token not configured. Pass { csrfToken: sessionToken } to handleActionRequest, or { skipCsrf: true } to explicitly opt out."}});let i=e?.headers?.["x-csrf-token"]||e?.headers?.["X-CSRF-Token"];if(!ge(i,s))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let o=K.get(t);return o?Array.isArray(r)?o.fn(...r).then(async i=>{let c=o.options||{};if(Array.isArray(c.revalidate))for(let u of c.revalidate)await X(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await Y(u);return{status:200,body:i}}).catch(i=>(console.error(`[what] Action "${t}" error:`,i),{status:500,body:{message:"Action failed"}})):Promise.resolve({status:400,body:{message:"Invalid action arguments"}}):Promise.resolve({status:404,body:{message:"Action not found"}})}function Ve(){return[...K.keys()]}function We(e,t={}){let{onSuccess:r,onError:n,onSettled:s}=t,a={isPending:R(!1),error:R(null),data:R(null)};async function o(...i){a.isPending.set(!0),a.error.set(null);try{let c=await e(...i);return a.data.set(c),r&&r(c,...i),c}catch(c){throw a.error.set(c),n&&n(c,...i),c}finally{a.isPending.set(!1),s&&s(a.data.peek(),a.error.peek(),...i)}}return{mutate:o,isPending:()=>a.isPending(),error:()=>a.error(),data:()=>a.data(),reset:()=>{a.error.set(null),a.data.set(null)}}}import{h as L}from"what-core";var _e="/__what_action";function ze(e){if(typeof e=="string")return e;if(typeof e=="function"){let t=e._actionId;if(t)return t;throw Object.assign(new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string."),{code:"ERR_FORM_ACTION_NOT_REGISTERED"})}throw Object.assign(new Error("[what] <Form> requires an `action` prop: a server action or its id."),{code:"ERR_FORM_ACTION_MISSING"})}function Xe(){if(typeof document>"u")return null;let e=document.querySelector('meta[name="what-csrf-token"]');if(e)return e.getAttribute("content");let t=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return t?decodeURIComponent(t[1]):null}function Ye({action:e,csrfToken:t,redirect:r,method:n="post",enhance:s=!0,children:a,...o}){let i=ze(e),c=t!==void 0?t:Xe();c==null&&typeof process<"u";let u=[L("input",{type:"hidden",name:"_action",value:i}),L("input",{type:"hidden",name:"what-csrf-token",value:c||""})];r&&u.push(L("input",{type:"hidden",name:"_redirect",value:r}));let d={...o,method:n,action:o.action||_e,"data-action":i};s&&(d["data-enhance"]="");let f=a==null?[]:Array.isArray(a)?a:[a];return L("form",d,...u,...f)}var Ge="/__what_action",Ae=1024*1024;function Ke(e){if(!e)return{};if(typeof e.forEach=="function"&&typeof e.get=="function"){let r={};return e.forEach((n,s)=>{r[s.toLowerCase()]=n}),r}let t={};for(let r in e)t[r.toLowerCase()]=e[r];return t}function M(e,t){return{status:e,headers:{"content-type":"application/json"},body:JSON.stringify(t)}}function q(e,t){return{status:e,headers:{"content-type":"text/html; charset=utf-8"},body:`<!DOCTYPE html><html><body><h1>${e}</h1><p>${String(t).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</p></body></html>`}}function Re(e){if(typeof e!="string"||!e.startsWith("/")||/^[/\\]{2}/.test(e)||e.includes("\\"))return null;try{let t=new URL(e,"http://localhost");return t.origin!=="http://localhost"?null:t.pathname+t.search}catch{return null}}function Ze(e,t){let r=Re(e&&e._redirect);if(r)return r;let n=t.referer||t.referrer;if(n)try{let s=new URL(n,"http://localhost"),a=Re(s.pathname+s.search);if(a)return a}catch{}return"/"}var Qe=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function N(e={}){let{getCsrfToken:t,skipCsrf:r=!1}=e;return async function(s){if((s.method||"POST").toUpperCase()!=="POST")return M(405,{message:"Method Not Allowed"});let o=Ke(s.headers),i=o["x-what-action"],c=o["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=r?void 0:t?await t(s):void 0;if(u){let h=s.body||{},w=h._action||h["data-action"]||s.query&&s.query.action;if(!w)return q(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let _={...o},C=h._csrf??h["what-csrf-token"];if(C&&!_["x-csrf-token"]&&(_["x-csrf-token"]=String(C)),!r&&t&&!d)return q(403,"Missing CSRF token");let O={};for(let[$,B]of Object.entries(h))Qe.has($)||(O[$]=B);let k=await j({headers:_},w,[O],{csrfToken:d,skipCsrf:r});return k.status===200?{status:303,headers:{location:Ze(h,o)},body:""}:q(k.status,k.body&&k.body.message||"Action failed")}if(!i)return M(400,{message:"Missing X-What-Action header"});if(!r&&t&&!d)return M(403,{message:"Missing CSRF token"});let l=(s.body||{}).args,p=await j({headers:o},i,l,{csrfToken:d,skipCsrf:r});return M(p.status,p.body)}}function qe(e={}){let t=e.basePath||Ge,r=N(e);return async function(s,a,o){let[i,c]=(s.url||"").split("?");if(i!==t||(s.method||"").toUpperCase()!=="POST")return o?o():void 0;let u;try{let l=await et(s);u=F(l,s.headers["content-type"]||"")}catch(l){a.writeHead(l.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),a.end(JSON.stringify({message:l.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let d=Object.fromEntries(new URLSearchParams(c||"")),f=await r({method:s.method,headers:s.headers,body:u,query:d});a.writeHead(f.status,f.headers),a.end(f.body)}}function F(e,t){if((t||"").includes("application/x-www-form-urlencoded")){let r={};for(let[n,s]of new URLSearchParams(String(e)))r[n]===void 0?r[n]=s:Array.isArray(r[n])?r[n].push(s):r[n]=[r[n],s];return r}return e==null||e===""?{}:JSON.parse(String(e))}async function U(e,t=Ae){let r=Number(e.headers.get("content-length"));if(Number.isFinite(r)&&r>t)return{tooLarge:!0};let n=e.body;if(!n||typeof n.getReader!="function"){let i=await e.text();return Buffer.byteLength(i,"utf8")>t?{tooLarge:!0}:{raw:i}}let s=n.getReader(),a=[],o=0;for(;;){let{done:i,value:c}=await s.read();if(i)break;if(c){if(o+=c.byteLength,o>t){try{await s.cancel()}catch{}return{tooLarge:!0}}a.push(c)}}return{raw:Buffer.concat(a.map(i=>Buffer.from(i))).toString("utf8")}}function et(e){return new Promise((t,r)=>{let n=0,s=[];e.on("data",a=>{if(n+=a.length,n>Ae){let o=new Error("Body too large");o.code="BODY_TOO_LARGE",r(o),e.destroy?.();return}s.push(a)}),e.on("end",()=>{if(s.length===0)return t("");t(Buffer.concat(s).toString("utf8"))}),e.on("error",r)})}function tt(e={}){let t=N(e);return async function(r){let n={};try{let o=await U(r);if(o.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});n=F(o.raw,r.headers.get("content-type")||"")}catch{n={}}let s={};try{s=Object.fromEntries(new URL(r.url,"http://localhost").searchParams)}catch{}let a=await t({method:r.method,headers:r.headers,body:n,query:s});return new Response(a.body,{status:a.status,headers:a.headers})}}import{matchRoute as rt,parseQuery as nt}from"what-router/match";var ot="/__what_action",at="/__what_revalidate",ee="what-csrf";function D(e){let t={};return e&&typeof e.forEach=="function"&&e.forEach((r,n)=>{t[n.toLowerCase()]=r}),t}function Ee(e,t){if(!e)return null;let r=String(e).match(new RegExp(`(?:^|;\\s*)${t}=([^;]+)`));return r?decodeURIComponent(r[1]):null}async function st(e){try{let t=await U(e);return t.tooLarge?{tooLarge:!0}:F(t.raw,e.headers.get("content-type")||"")}catch{return{}}}async function it(e){let t;try{t=await U(e)}catch{return{json:{}}}if(t.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(t.raw??"")}}catch{return{json:{}}}}function ct(e){return async function(r){let{route:n,params:s,query:a,request:o,csrfToken:i}=r,c={default:n.component,loader:n.loader},u=i?{params:s,query:a,request:o,csrfToken:i}:{params:s,query:a,request:o},d=i?{...e,csrfToken:i}:e;return{html:await Te(c,u,d),status:200,tags:r.config&&r.config.tags||[],path:r.path}}}function te(e={}){let{routes:t=[],cache:r,render:n,revalidateWebhook:s,document:a={},notFound:o,basePath:i="",csrf:c=!0}=e,u=c!==!1&&!e.actionHandler,d=e.actionHandler||N(u?{getCsrfToken:l=>Ee(l.headers&&l.headers.cookie,ee)}:{skipCsrf:!0}),f=n||ct(a);return r&&(r.revalidatePath||r.revalidateTag)&&z({revalidatePath:r.revalidatePath,revalidateTag:r.revalidateTag}),async function(p){let h=new URL(p.url,"http://localhost"),w=h.pathname;if(i&&w.startsWith(i)&&(w=w.slice(i.length)||"/"),p.method==="POST"&&w===ot){let m=await st(p);if(m&&m.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let E=await d({method:"POST",headers:D(p.headers),body:m,query:Object.fromEntries(h.searchParams)});return new Response(E.body,{status:E.status,headers:E.headers})}let _=null,C=null;if(u&&(_=Ee(D(p.headers).cookie,ee),!_)){_=Z();let E=D(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;C=`${ee}=${encodeURIComponent(_)}; Path=/; SameSite=Lax`+(E?"; Secure":"")}let O=m=>(C&&(m["set-cookie"]=C),m);if(p.method==="POST"&&w===at&&s){let m=await it(p);if(m.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let E=await s({headers:D(p.headers),body:m.json});return new Response(JSON.stringify(E.body),{status:E.status,headers:{"content-type":"application/json"}})}let k=rt(w,t);if(!k){let m=o?o():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(m,{status:404,headers:O({"content-type":"text/html; charset=utf-8"})})}let{route:$,params:B}=k,J=$.page||{mode:$.mode||"client"},v={path:w,query:nt(h.search),config:J,route:$,params:B,request:p};if(r&&J.mode!=="server"){v.varyHeaders=D(p.headers);let m=await r.handle(v,()=>f(v));return new Response(m.html,{status:m.status||200,headers:O({"content-type":"text/html; charset=utf-8",...m.headers||{}})})}_&&(v.csrfToken=_);let V=await f(v),he=O({"content-type":"text/html; charset=utf-8",...V.headers||{}});return J.mode==="server"&&(he["Cache-Control"]="private, no-store"),new Response(V.html,{status:V.status||200,headers:he})}}function ut(e={}){let t=te(e);return{async fetch(r,n,s){return n&&(r.__env=n),s&&(r.__ctx=s),t(r)}}}function T(e){return{head:ft(),loaderData:e,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var Ce=0;function lt(){Ce=0}function pt(){return"h"+Ce++}function ht(e){if(!ke()){let t=T(void 0);return S(t,()=>ht(e))}return lt(),A(e)}var Oe=new Set(["__errorBoundary","__suspense"]),ie=new Set(["__portal"]);function ce(e){let t=e.children;return!t||t.length===0?{...e.props}:{...e.props,children:t}}function ue(e,t){let r=e.props&&e.props.fallback;if(typeof r!="function")return r;let n=e.props&&e.props.reset||(()=>{});try{return r({error:t,reset:n})}catch(s){return b(s),I&&console.warn(`[what-server] <ErrorBoundary> fallback threw during SSR: ${s.message}`),null}}function A(e){if(e==null||e===!1||e===!0)return"";if(typeof e=="string"||typeof e=="number")return g(String(e));if(typeof e=="function"&&e._signal)return`<!--$-->${A(e())}<!--/$-->`;if(typeof e=="function"&&e._mapArray)try{return`<!--$-->${A(ae(e))}<!--/$-->`}catch(c){return b(c),typeof process<"u","<!--$--><!--/$-->"}if(typeof e=="function")try{return`<!--$-->${A(e())}<!--/$-->`}catch(c){return b(c),typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(e))return`<!--[]-->${e.map(A).join("")}<!--/[]-->`;if(ie.has(e.tag))return"";if(Oe.has(e.tag))try{return(e.children||[]).map(A).join("")}catch(c){b(c);let u=c&&typeof c.then=="function";if(u&&e.tag==="__errorBoundary"||!u&&e.tag==="__suspense")throw c;return A(ue(e,u?null:c))}if(typeof e.tag=="function"){let c=pt(),u=ne(e.tag),d;try{d=A(e.tag(ce(e)))}finally{oe(u)}return yt(d,c)}let{tag:t,props:r,children:n}=e;fe(t,e);let s=le(r||{}),a=`<${t}${s}>`;if(pe.has(t))return a;let o=de(r),i=o!=null?String(o):n.map(A).join("");return`${a}${i}</${t}>`}function yt(e,t){let r=e.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(r){let n=r[1],s=r[2],a=n.length+1+s.length,o=e.indexOf(">",a),i=e.slice(a,o===-1?void 0:o);return/[\s"']data-hk\s*=/.test(i)||/^\s*data-hk\s*=/.test(i)?e:e.slice(0,a)+` data-hk="${t}"`+e.slice(a)}return e}function y(e){if(!ke()){let c=T(void 0);return S(c,()=>y(e))}if(e==null||e===!1||e===!0)return"";if(typeof e=="string"||typeof e=="number")return g(String(e));if(typeof e=="function"&&e._signal)return y(e());if(typeof e=="function"&&e._mapArray)try{return y(ae(e))}catch(c){return b(c),typeof process<"u",""}if(typeof e=="function")try{return y(e())}catch(c){return b(c),typeof process<"u",""}if(Array.isArray(e))return e.map(y).join("");if(ie.has(e.tag))return"";if(Oe.has(e.tag))try{return(e.children||[]).map(y).join("")}catch(c){b(c);let u=c&&typeof c.then=="function";if(u&&e.tag==="__errorBoundary"||!u&&e.tag==="__suspense")throw c;return y(ue(e,u?null:c))}if(typeof e.tag=="function"){let c=ne(e.tag);try{return y(e.tag(ce(e)))}finally{oe(c)}}let{tag:t,props:r,children:n}=e;fe(t,e);let s=le(r||{}),a=`<${t}${s}>`;if(pe.has(t))return a;let o=de(r),i=o!=null?String(o):n.map(y).join("");return`${a}${i}</${t}>`}function qt(e){let t=T(void 0);return{body:S(t,()=>y(e)),head:se(t.head)}}async function er(e,t={}){let r=e.default||e,n=typeof e.loader=="function"?await e.loader(t):void 0,s=T(n),a=t.params||{};return{body:S(s,()=>y(re(r,{...a,loaderData:n}))),head:se(s.head),loaderData:n}}var $e=12;async function mt(e,t){t||(t=T(void 0));let r="",n=t.resourceCounter;for(let a=0;a<$e;a++){t.resourceCounter=n,r=S(t,()=>y(e));let o=[...t.resources.values()].filter(i=>i.status==="pending").map(i=>i.promise);if(o.length===0)break;await Promise.all(o)}let s={};for(let[a,o]of t.resources)o.status==="ready"&&(s[a]=o.value);return{body:r,head:se(t.head),loaderData:t.loaderData,resources:s,ctx:t}}async function Te(e,t={},r={}){let n=e.default||e,s=typeof e.loader=="function"?await e.loader(t):void 0,a=T(s),o=t.params||{},{body:i,head:c,resources:u}=await mt(re(n,{...o,loaderData:s}),a),d={loaderData:s??null,resources:u,islandStores:ye(a)};return gt({body:i,head:c,payload:d,options:r})}function gt({body:e,head:t,payload:r,options:n={}}){let s=n.lang||"en",a=`<script id="__what_data" type="application/json">${W(r)}<\/script>`,o=n.clientEntry?`<script type="module" src="${g(n.clientEntry)}"><\/script>`:"",c=(n.csrfToken?Q(n.csrfToken):"")+(n.head||""),u=n.bodyClass?` class="${g(n.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${g(s)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${t||""}${c}</head><body${u}>${e}${a}${o}</body></html>`}async function*P(e,t){if(t===void 0&&(t=T(void 0)),e==null||e===!1||e===!0)return;if(typeof e=="string"||typeof e=="number"){yield g(String(e));return}if(typeof e=="function"&&e._signal){let o=S(t,()=>e());yield*P(o,t);return}if(typeof e=="function"&&e._mapArray){let o=null;try{o=S(t,()=>ae(e))}catch(i){b(i),typeof process<"u"}o&&(yield*P(o,t));return}if(typeof e=="function"){try{let o=S(t,()=>e());yield*P(o,t)}catch(o){b(o),typeof process<"u"}return}if(Array.isArray(e)){for(let o of e)yield*P(o,t);return}if(ie.has(e.tag))return;if(e.tag==="__errorBoundary"){let o;try{o=S(t,()=>(e.children||[]).map(y).join(""))}catch(i){if(b(i),i&&typeof i.then=="function")throw i;o=S(t,()=>y(ue(e,i)))}yield o;return}if(e.tag==="__suspense"){let o=null,i=t.resourceCounter;for(let c=0;c<$e&&o===null;c++){t.resourceCounter=i;let u=null;try{o=S(t,()=>(e.children||[]).map(y).join(""))}catch(d){if(d&&typeof d.then=="function")u=d;else throw d}if(o===null){let d=[...t.resources.values()].filter(f=>f.status==="pending").map(f=>f.promise);await Promise.all([u,...d].filter(Boolean))}}o===null&&(o=S(t,()=>y(e.props&&e.props.fallback))),yield o;return}if(typeof e.tag=="function"){let o=ne(e.tag);try{let i=S(t,()=>e.tag(ce(e))),c=i instanceof Promise?await i:i;yield*P(c,t)}catch(i){b(i),typeof process<"u",yield I?`<!-- SSR Error: ${g(i.message||"Component error")} -->`:"<!-- SSR Error -->"}finally{oe(o)}return}let{tag:r,props:n,children:s}=e;fe(r,e);let a=le(n||{});if(yield`<${r}${a}>`,!pe.has(r)){let o=de(n);if(o!=null)yield String(o);else for(let i of s)yield*P(i,t);yield`</${r}>`}}function tr(e){return{mode:"static",...e}}function rr(e,t={}){let r=T(t),n=S(r,()=>y(re(e.component,t))),s=e.islands||[];return wt({title:e.title||"",meta:e.meta||{},body:n,islands:s,scripts:e.mode==="static"?[]:e.scripts||[],styles:e.styles||[],mode:e.mode})}function wt({title:e,meta:t,body:r,islands:n,scripts:s,styles:a,mode:o}){let i=Object.entries(t).map(([l,p])=>`<meta name="${g(l)}" content="${g(p)}">`).join(`
2
2
  `),c=a.map(l=>`<link rel="stylesheet" href="${g(l)}">`).join(`
3
- `),u=r.length>0?`
3
+ `),u=n.length>0?`
4
4
  <script type="module">
5
5
  import { hydrateIslands } from '/@what/islands.js';
6
6
  hydrateIslands();
@@ -12,13 +12,13 @@ import{h as et,_isAriaAttr as ue,_beginComponentSSR as nt,_endComponentSSR as rt
12
12
  <meta charset="UTF-8">
13
13
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
14
14
  ${i}
15
- <title>${g(t)}</title>
15
+ <title>${g(e)}</title>
16
16
  ${c}
17
17
  </head>
18
18
  <body>
19
- <div id="app">${n}</div>
19
+ <div id="app">${r}</div>
20
20
  ${u}
21
21
  ${d}
22
22
  ${f}
23
23
  </body>
24
- </html>`}function en(t){return t._server=!0,t}var P=!(typeof process<"u");function ut(t){return t?t.dangerouslySetInnerHTML?t.dangerouslySetInnerHTML.__html??null:t.innerHTML&&typeof t.innerHTML=="object"&&"__html"in t.innerHTML?t.innerHTML.__html??null:(t.innerHTML!=null&&typeof t.innerHTML=="string"&&P&&console.warn("[what-server] innerHTML received a raw string. This is a security risk (XSS). Use innerHTML={{ __html: trustedString }} or dangerouslySetInnerHTML={{ __html: trustedString }} instead."),null):null}var we=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,Se=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function dt(t){if(typeof t!="string"||!Se.test(t))throw Object.assign(new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(t)}`),{code:"ERR_INVALID_SSR_TAG"})}function ft(t){let e="";for(let[n,r]of Object.entries(t)){if(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")continue;let s=n.toLowerCase();if(s.startsWith("on")&&n.length>2)continue;let a=r;if(typeof a=="function"){try{a=a()}catch(o){P&&console.warn(`[what-server] Skipping attribute ${JSON.stringify(n)}: its value threw during SSR: ${o.message}`);continue}if(typeof a=="function")continue}if(a===!1&&ue(n)){e+=` ${n}="false"`;continue}if(!(a===!1||a==null)){if(!we.test(n)){P&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(Re.has(s)){P&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")e+=` class="${g(String(a))}"`;else if(n==="style"&&typeof a=="object"){let o=Object.entries(a).map(([i,c])=>`${Ae(i)}:${c}`).join(";");e+=` style="${g(o)}"`}else if(a===!0)n.startsWith("aria-")||n==="role"?e+=` ${n}="true"`:e+=` ${n}`;else{if(be(n,a))continue;e+=` ${n}="${g(String(a))}"`}}}return e}function be(t,e){let n=t.toLowerCase();if(!_e.has(n))return!1;let r=String(e).trim().replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();return r.startsWith("javascript:")||r.startsWith("vbscript:")||r.startsWith("data:")}var _e=new Set(["href","src","action","formaction","data","ping","xlink:href"]),Re=new Set(["srcdoc"]);function g(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function Ae(t){return t.startsWith("--")?t:t.replace(/([A-Z])/g,"-$1").toLowerCase()}var lt=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);export{bt as ACTION_ENDPOINT,Yt as Form,Mt as action,I as createActionHandler,ce as createCloudflareHandler,tt as createRequestHandler,Z as csrfMetaTag,qe as definePage,te as fetchActionHandler,gt as formAction,K as generateCsrfToken,tn as generateStaticPage,Jt as getRegisteredActions,Nt as getRevalidationHandler,H as handleActionRequest,St as invalidatePath,Qt as nodeActionMiddleware,Bt as onRevalidate,Et as renderDocument,Qe as renderPage,pe as renderToHydratableString,$ as renderToStream,y as renderToString,ye as renderToStringAsync,Ze as renderToStringWithHead,z as revalidatePath,Y as revalidateTag,V as serializeState,en as server,W as setRevalidationHandler,wt as useAction,Ft as useFormAction,Vt as useMutation,Ut as useOptimistic,mt as validateCsrfToken};
24
+ </html>`}function nr(e){return e._server=!0,e}var I=!(typeof process<"u");function de(e){return e?e.dangerouslySetInnerHTML?e.dangerouslySetInnerHTML.__html??null:e.innerHTML&&typeof e.innerHTML=="object"&&"__html"in e.innerHTML?e.innerHTML.__html??null:(e.innerHTML!=null&&typeof e.innerHTML=="string"&&I&&console.warn("[what-server] innerHTML received a raw string. This is a security risk (XSS). Use innerHTML={{ __html: trustedString }} or dangerouslySetInnerHTML={{ __html: trustedString }} instead."),null):null}var St=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,bt=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function b(e){if(e&&e.code==="ERR_COMPILED_JSX_IN_SSR")throw e}function _t(e){return!!e&&typeof e=="object"&&typeof e.nodeType=="number"}function fe(e,t){if(!(typeof e=="string"&&bt.test(e)))throw _t(t)?Object.assign(new Error('[what-server] Cannot server-render a DOM node. A component compiled by what-compiler returns a cloned template (finished DOM), not a vnode, so it has no server-rendered form. Author server-rendered views with h(), or compile them with the automatic JSX runtime (jsxImportSource: "what-framework") instead of what-compiler.'),{code:"ERR_COMPILED_JSX_IN_SSR"}):Object.assign(new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(e)}`),{code:"ERR_INVALID_SSR_TAG"})}function le(e){let t="";for(let[r,n]of Object.entries(e)){if(r==="key"||r==="ref"||r==="children"||r==="dangerouslySetInnerHTML"||r==="innerHTML")continue;let s=r.toLowerCase();if(s.startsWith("on")&&r.length>2)continue;let a=n;if(typeof a=="function"){try{a=a()}catch(o){I&&console.warn(`[what-server] Skipping attribute ${JSON.stringify(r)}: its value threw during SSR: ${o.message}`);continue}if(typeof a=="function")continue}if(a===!1&&(dt(r)||r.startsWith("data-"))){t+=` ${r}="false"`;continue}if(!(a===!1||a==null)){if(!St.test(r)){I&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(r)}`);continue}if(Et.has(s)){I&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(r)}`);continue}if(r==="className"||r==="class")t+=` class="${g(String(a))}"`;else if(r==="style"&&typeof a=="object"){let o=Object.entries(a).map(([i,c])=>`${Tt(i)}:${c}`).join(";");t+=` style="${g(o)}"`}else if(a===!0)r.startsWith("aria-")||r==="role"||r.startsWith("data-")?t+=` ${r}="true"`:t+=` ${r}`;else{if(Rt(r,a))continue;t+=` ${r}="${g(String(a))}"`}}}return t}function Rt(e,t){let r=e.toLowerCase();if(!At.has(r))return!1;let n=String(t).trim().replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();return n.startsWith("javascript:")||n.startsWith("vbscript:")||n.startsWith("data:")}var At=new Set(["href","src","action","formaction","data","ping","xlink:href"]),Et=new Set(["srcdoc"]);function g(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function Tt(e){return e.startsWith("--")?e:e.replace(/([A-Z])/g,"-$1").toLowerCase()}var pe=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);export{_e as ACTION_ENDPOINT,Ye as Form,Fe as action,N as createActionHandler,ut as createCloudflareHandler,te as createRequestHandler,Q as csrfMetaTag,tr as definePage,tt as fetchActionHandler,we as formAction,Z as generateCsrfToken,rr as generateStaticPage,Ve as getRegisteredActions,De as getRevalidationHandler,j as handleActionRequest,be as invalidatePath,qe as nodeActionMiddleware,Je as onRevalidate,Te as renderDocument,er as renderPage,ht as renderToHydratableString,P as renderToStream,y as renderToString,mt as renderToStringAsync,qt as renderToStringWithHead,X as revalidatePath,Y as revalidateTag,W as serializeState,nr as server,z as setRevalidationHandler,Se as useAction,Ue as useFormAction,We as useMutation,Be as useOptimistic,ge as validateCsrfToken};
package/dist/node.min.js CHANGED
@@ -1,11 +1,11 @@
1
- import{AsyncLocalStorage as Je}from"node:async_hooks";import{__installServerContextStorage as We}from"what-core";import{h as ot,_isAriaAttr as ge,_beginComponentSSR as at,_endComponentSSR as st,_mapArrayToArray as it,getServerContext as Ct,runWithServerContext as S,beginHeadCollection as we,endHeadCollection as ct}from"what-core";var Dt=new RegExp("[<>&\\u2028\\u2029]","g"),Lt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function N(t){return JSON.stringify(t).replace(Dt,e=>Lt[e.charCodeAt(0)])}import{mount as Ye,hydrate as Xe,signal as Ke,batch as Ze,getServerContext as Mt}from"what-core";var Ft=new Map;function Ut(t){let e=t||Mt();return e&&e.islandStores instanceof Map?e.islandStores:null}function St(t){let e=typeof document<"u"?Ft:Ut(t),n={};for(let[r,s]of e||[])n[r]=s._getSnapshot();return n}import{signal as _,batch as Q}from"what-core";var L=Symbol.for("what.revalidationHandler"),bt=!(typeof process<"u");function X(t){globalThis[L]=t}function Bt(){return globalThis[L]??null}async function K(t,e){let n=globalThis[L];if(n&&n.revalidatePath)return n.revalidatePath(t,e);bt&&console.warn(`[what] revalidatePath('${t}') had no effect: no cache engine is bound. Create a what-isr engine and bind it in your adapter (setRevalidationHandler).`)}async function Z(t,e){let n=globalThis[L];if(n&&n.revalidateTag)return n.revalidateTag(t,e);bt&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var q=new Map;function Vt(){if(typeof document<"u"){let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);if(e)return decodeURIComponent(e[1])}return null}function tt(){if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let t=new Uint8Array(16);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}throw Object.assign(new Error("[what] No secure random source available for CSRF token generation"),{code:"ERR_NO_SECURE_RANDOM"})}function _t(t,e){if(!t||!e||t.length!==e.length)return!1;let n=0;for(let r=0;r<t.length;r++)n|=t.charCodeAt(r)^e.charCodeAt(r);return n===0}function et(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}">`}var Jt=0,Wt=!1;function zt(){return!Wt&&typeof process<"u",`a_${typeof crypto<"u"&&crypto.getRandomValues?Array.from(crypto.getRandomValues(new Uint8Array(6)),e=>e.toString(16).padStart(2,"0")).join(""):`c${(++Jt).toString(36)}_${Date.now().toString(36)}`}`}function Gt(t,e={}){let n=e.id||zt(),{onError:r,onSuccess:s,revalidate:o}=e;typeof window>"u"&&q.set(n,{fn:t,options:e});async function a(...i){if(typeof window>"u")return t(...i);let c=e.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let f=Vt(),l={"Content-Type":"application/json","X-What-Action":n};f&&(l["X-CSRF-Token"]=f);let p=await fetch("/__what_action",{method:"POST",headers:l,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let y=await p.json().catch(()=>({message:"Action failed"}));throw Object.assign(new Error(y.message||"Action failed"),{code:"ERR_ACTION_FAILED"})}let h=await p.json();if(s&&s(h),o)for(let y of o)At(y);return h}catch(f){if(f.name==="AbortError"){let l=new Error(`Action "${n}" timed out after ${c}ms`);throw l.code="TIMEOUT",r&&r(l),l}throw r&&r(f),f}finally{clearTimeout(d)}}return a._actionId=n,a._isAction=!0,a}function Rt(t,e={}){let{onSuccess:n,onError:r,resetOnSuccess:s=!0}=e;return async o=>{let a,i;o instanceof Event?(o.preventDefault(),i=o.target,a=new FormData(i)):a=o;let c={},u=!1;for(let[d,f]of a.entries())typeof File<"u"&&f instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(f):c[d]=[c[d],f]:c[d]=f;try{let d=u?await t(c,a):await t(c);return n&&n(d,i),s&&i&&i.reset(),d}catch(d){throw r&&r(d,i),d}}}function Et(t){let e=_(!1),n=_(null),r=_(null);async function s(...o){e.set(!0),n.set(null);try{let a=await t(...o);return r.set(a),a}catch(a){throw n.set(a),a}finally{e.set(!1)}}return{trigger:s,isPending:()=>e(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Yt(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},s=Et(Rt(t,{resetOnSuccess:n}));function o(a){a.preventDefault();let i=new FormData(a.target);return r.current=a.target,s.trigger(i)}return{...s,handleSubmit:o,formRef:r}}function Xt(t,e){let n=_(t),r=_([]),s=_(t);function o(u){let d=e(n.peek(),u);Q(()=>{r.set([...r.peek(),u]),n.set(d)})}function a(u,d){Q(()=>{if(r.set(r.peek().filter(f=>f!==u)),d!==void 0){s.set(d);let f=d;for(let l of r.peek())f=e(f,l);n.set(f)}})}function i(u,d){Q(()=>{let f=r.peek().filter(h=>h!==u);r.set(f);let l=d!==void 0?d:s.peek();s.set(l);let p=l;for(let h of f)p=e(p,h);n.set(p)})}async function c(u,d){o(u);try{let f=await d();return a(u,f),f}catch(f){throw i(u),f}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:o,resolve:a,rollback:i,withOptimistic:c,set:u=>{n.set(u),s.set(u)}}}var I=new Map;function Kt(t,e){return I.has(t)||I.set(t,new Set),I.get(t).add(e),()=>{I.get(t)?.delete(e)}}function At(t){let e=I.get(t);if(e)for(let n of e)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function M(t,e,n,r={}){let{csrfToken:s,skipCsrf:o=!1}=r;if(!o){if(!s)return Promise.resolve({status:500,body:{message:"[what] CSRF token not configured. Pass { csrfToken: sessionToken } to handleActionRequest, or { skipCsrf: true } to explicitly opt out."}});let i=t?.headers?.["x-csrf-token"]||t?.headers?.["X-CSRF-Token"];if(!_t(i,s))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let a=q.get(e);return a?Array.isArray(n)?a.fn(...n).then(async i=>{let c=a.options||{};if(Array.isArray(c.revalidate))for(let u of c.revalidate)await K(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await Z(u);return{status:200,body:i}}).catch(i=>(console.error(`[what] Action "${e}" error:`,i),{status:500,body:{message:"Action failed"}})):Promise.resolve({status:400,body:{message:"Invalid action arguments"}}):Promise.resolve({status:404,body:{message:"Action not found"}})}function Zt(){return[...q.keys()]}function Qt(t,e={}){let{onSuccess:n,onError:r,onSettled:s}=e,o={isPending:_(!1),error:_(null),data:_(null)};async function a(...i){o.isPending.set(!0),o.error.set(null);try{let c=await t(...i);return o.data.set(c),n&&n(c,...i),c}catch(c){throw o.error.set(c),r&&r(c,...i),c}finally{o.isPending.set(!1),s&&s(o.data.peek(),o.error.peek(),...i)}}return{mutate:a,isPending:()=>o.isPending(),error:()=>o.error(),data:()=>o.data(),reset:()=>{o.error.set(null),o.data.set(null)}}}import{h as F}from"what-core";var Tt="/__what_action";function qt(t){if(typeof t=="string")return t;if(typeof t=="function"){let e=t._actionId;if(e)return e;throw Object.assign(new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string."),{code:"ERR_FORM_ACTION_NOT_REGISTERED"})}throw Object.assign(new Error("[what] <Form> requires an `action` prop: a server action or its id."),{code:"ERR_FORM_ACTION_MISSING"})}function te(){if(typeof document>"u")return null;let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return e?decodeURIComponent(e[1]):null}function ee({action:t,csrfToken:e,redirect:n,method:r="post",enhance:s=!0,children:o,...a}){let i=qt(t),c=e!==void 0?e:te();c==null&&typeof process<"u";let u=[F("input",{type:"hidden",name:"_action",value:i}),F("input",{type:"hidden",name:"what-csrf-token",value:c||""})];n&&u.push(F("input",{type:"hidden",name:"_redirect",value:n}));let d={...a,method:r,action:a.action||Tt,"data-action":i};s&&(d["data-enhance"]="");let f=o==null?[]:Array.isArray(o)?o:[o];return F("form",d,...u,...f)}var ne="/__what_action",j=1024*1024;function re(t){if(!t)return{};if(typeof t.forEach=="function"&&typeof t.get=="function"){let n={};return t.forEach((r,s)=>{n[s.toLowerCase()]=r}),n}let e={};for(let n in t)e[n.toLowerCase()]=t[n];return e}function U(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function nt(t,e){return{status:t,headers:{"content-type":"text/html; charset=utf-8"},body:`<!DOCTYPE html><html><body><h1>${t}</h1><p>${String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</p></body></html>`}}function kt(t){if(typeof t!="string"||!t.startsWith("/")||/^[/\\]{2}/.test(t)||t.includes("\\"))return null;try{let e=new URL(t,"http://localhost");return e.origin!=="http://localhost"?null:e.pathname+e.search}catch{return null}}function oe(t,e){let n=kt(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let s=new URL(r,"http://localhost"),o=kt(s.pathname+s.search);if(o)return o}catch{}return"/"}var ae=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function H(t={}){let{getCsrfToken:e,skipCsrf:n=!1}=t;return async function(s){if((s.method||"POST").toUpperCase()!=="POST")return U(405,{message:"Method Not Allowed"});let a=re(s.headers),i=a["x-what-action"],c=a["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=n?void 0:e?await e(s):void 0;if(u){let h=s.body||{},y=h._action||h["data-action"]||s.query&&s.query.action;if(!y)return nt(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let b={...a},O=h._csrf??h["what-csrf-token"];if(O&&!b["x-csrf-token"]&&(b["x-csrf-token"]=String(O)),!n&&e&&!d)return nt(403,"Missing CSRF token");let C={};for(let[v,z]of Object.entries(h))ae.has(v)||(C[v]=z);let k=await M({headers:b},y,[C],{csrfToken:d,skipCsrf:n});return k.status===200?{status:303,headers:{location:oe(h,a)},body:""}:nt(k.status,k.body&&k.body.message||"Action failed")}if(!i)return U(400,{message:"Missing X-What-Action header"});if(!n&&e&&!d)return U(403,{message:"Missing CSRF token"});let l=(s.body||{}).args,p=await M({headers:a},i,l,{csrfToken:d,skipCsrf:n});return U(p.status,p.body)}}function se(t={}){let e=t.basePath||ne,n=H(t);return async function(s,o,a){let[i,c]=(s.url||"").split("?");if(i!==e||(s.method||"").toUpperCase()!=="POST")return a?a():void 0;let u;try{let l=await ie(s);u=B(l,s.headers["content-type"]||"")}catch(l){o.writeHead(l.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),o.end(JSON.stringify({message:l.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let d=Object.fromEntries(new URLSearchParams(c||"")),f=await n({method:s.method,headers:s.headers,body:u,query:d});o.writeHead(f.status,f.headers),o.end(f.body)}}function B(t,e){if((e||"").includes("application/x-www-form-urlencoded")){let n={};for(let[r,s]of new URLSearchParams(String(t)))n[r]===void 0?n[r]=s:Array.isArray(n[r])?n[r].push(s):n[r]=[n[r],s];return n}return t==null||t===""?{}:JSON.parse(String(t))}async function V(t,e=j){let n=Number(t.headers.get("content-length"));if(Number.isFinite(n)&&n>e)return{tooLarge:!0};let r=t.body;if(!r||typeof r.getReader!="function"){let i=await t.text();return Buffer.byteLength(i,"utf8")>e?{tooLarge:!0}:{raw:i}}let s=r.getReader(),o=[],a=0;for(;;){let{done:i,value:c}=await s.read();if(i)break;if(c){if(a+=c.byteLength,a>e){try{await s.cancel()}catch{}return{tooLarge:!0}}o.push(c)}}return{raw:Buffer.concat(o.map(i=>Buffer.from(i))).toString("utf8")}}function ie(t){return new Promise((e,n)=>{let r=0,s=[];t.on("data",o=>{if(r+=o.length,r>j){let a=new Error("Body too large");a.code="BODY_TOO_LARGE",n(a),t.destroy?.();return}s.push(o)}),t.on("end",()=>{if(s.length===0)return e("");e(Buffer.concat(s).toString("utf8"))}),t.on("error",n)})}function ce(t={}){let e=H(t);return async function(n){let r={};try{let a=await V(n);if(a.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=B(a.raw,n.headers.get("content-type")||"")}catch{r={}}let s={};try{s=Object.fromEntries(new URL(n.url,"http://localhost").searchParams)}catch{}let o=await e({method:n.method,headers:n.headers,body:r,query:s});return new Response(o.body,{status:o.status,headers:o.headers})}}import{matchRoute as ue,parseQuery as de}from"what-router/match";var fe="/__what_action",le="/__what_revalidate",rt="what-csrf";function D(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((n,r)=>{e[r.toLowerCase()]=n}),e}function Ot(t,e){if(!t)return null;let n=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function pe(t){try{let e=await V(t);return e.tooLarge?{tooLarge:!0}:B(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function he(t){let e;try{e=await V(t)}catch{return{json:{}}}if(e.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(e.raw??"")}}catch{return{json:{}}}}function ye(t){return async function(n){let{route:r,params:s,query:o,request:a,csrfToken:i}=n,c={default:r.component,loader:r.loader},u=i?{params:s,query:o,request:a,csrfToken:i}:{params:s,query:o,request:a},d=i?{...t,csrfToken:i}:t;return{html:await J(c,u,d),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function A(t={}){let{routes:e=[],cache:n,render:r,revalidateWebhook:s,document:o={},notFound:a,basePath:i="",csrf:c=!0}=t,u=c!==!1&&!t.actionHandler,d=t.actionHandler||H(u?{getCsrfToken:l=>Ot(l.headers&&l.headers.cookie,rt)}:{skipCsrf:!0}),f=r||ye(o);return n&&(n.revalidatePath||n.revalidateTag)&&X({revalidatePath:n.revalidatePath,revalidateTag:n.revalidateTag}),async function(p){let h=new URL(p.url,"http://localhost"),y=h.pathname;if(i&&y.startsWith(i)&&(y=y.slice(i.length)||"/"),p.method==="POST"&&y===fe){let g=await pe(p);if(g&&g.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let E=await d({method:"POST",headers:D(p.headers),body:g,query:Object.fromEntries(h.searchParams)});return new Response(E.body,{status:E.status,headers:E.headers})}let b=null,O=null;if(u&&(b=Ot(D(p.headers).cookie,rt),!b)){b=tt();let E=D(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;O=`${rt}=${encodeURIComponent(b)}; Path=/; SameSite=Lax`+(E?"; Secure":"")}let C=g=>(O&&(g["set-cookie"]=O),g);if(p.method==="POST"&&y===le&&s){let g=await he(p);if(g.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let E=await s({headers:D(p.headers),body:g.json});return new Response(JSON.stringify(E.body),{status:E.status,headers:{"content-type":"application/json"}})}let k=ue(y,e);if(!k){let g=a?a():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(g,{status:404,headers:C({"content-type":"text/html; charset=utf-8"})})}let{route:v,params:z}=k,G=v.page||{mode:v.mode||"client"},P={path:y,query:de(h.search),config:G,route:v,params:z,request:p};if(n&&G.mode!=="server"){P.varyHeaders=D(p.headers);let g=await n.handle(P,()=>f(P));return new Response(g.html,{status:g.status||200,headers:C({"content-type":"text/html; charset=utf-8",...g.headers||{}})})}b&&(P.csrfToken=b);let Y=await f(P),wt=C({"content-type":"text/html; charset=utf-8",...Y.headers||{}});return G.mode==="server"&&(wt["Cache-Control"]="private, no-store"),new Response(Y.html,{status:Y.status||200,headers:wt})}}function me(t={}){let e=A(t);return{async fetch(n,r,s){return r&&(n.__env=r),s&&(n.__ctx=s),e(n)}}}function T(t){return{head:we(),loaderData:t,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var vt=0;function Se(){vt=0}function be(){return"h"+vt++}function _e(t){if(!Ct()){let e=T(void 0);return S(e,()=>_e(t))}return Se(),R(t)}var xt=new Set(["__errorBoundary","__suspense"]),ut=new Set(["__portal"]);function dt(t){let e=t.children;return!e||e.length===0?{...t.props}:{...t.props,children:e}}function ft(t,e){let n=t.props&&t.props.fallback;if(typeof n!="function")return n;let r=t.props&&t.props.reset||(()=>{});try{return n({error:e,reset:r})}catch(s){return $&&console.warn(`[what-server] <ErrorBoundary> fallback threw during SSR: ${s.message}`),null}}function R(t){if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return w(String(t));if(typeof t=="function"&&t._signal)return`<!--$-->${R(t())}<!--/$-->`;if(typeof t=="function"&&t._mapArray)try{return`<!--$-->${R(it(t))}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(typeof t=="function")try{return`<!--$-->${R(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(R).join("")}<!--/[]-->`;if(ut.has(t.tag))return"";if(xt.has(t.tag))try{return(t.children||[]).map(R).join("")}catch(c){let u=c&&typeof c.then=="function";if(u&&t.tag==="__errorBoundary"||!u&&t.tag==="__suspense")throw c;return R(ft(t,u?null:c))}if(typeof t.tag=="function"){let c=be(),u=at(t.tag),d;try{d=R(t.tag(dt(t)))}finally{st(u)}return Re(d,c)}let{tag:e,props:n,children:r}=t;pt(e);let s=ht(n||{}),o=`<${e}${s}>`;if(yt.has(e))return o;let a=lt(n),i=a!=null?String(a):r.map(R).join("");return`${o}${i}</${e}>`}function Re(t,e){let n=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],s=n[2],o=r.length+1+s.length,a=t.indexOf(">",o),i=t.slice(o,a===-1?void 0:a);return/[\s"']data-hk\s*=/.test(i)||/^\s*data-hk\s*=/.test(i)?t:t.slice(0,o)+` data-hk="${e}"`+t.slice(o)}return t}function m(t){if(!Ct()){let c=T(void 0);return S(c,()=>m(t))}if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return w(String(t));if(typeof t=="function"&&t._signal)return m(t());if(typeof t=="function"&&t._mapArray)try{return m(it(t))}catch{return typeof process<"u",""}if(typeof t=="function")try{return m(t())}catch{return typeof process<"u",""}if(Array.isArray(t))return t.map(m).join("");if(ut.has(t.tag))return"";if(xt.has(t.tag))try{return(t.children||[]).map(m).join("")}catch(c){let u=c&&typeof c.then=="function";if(u&&t.tag==="__errorBoundary"||!u&&t.tag==="__suspense")throw c;return m(ft(t,u?null:c))}if(typeof t.tag=="function"){let c=at(t.tag);try{return m(t.tag(dt(t)))}finally{st(c)}}let{tag:e,props:n,children:r}=t;pt(e);let s=ht(n||{}),o=`<${e}${s}>`;if(yt.has(e))return o;let a=lt(n),i=a!=null?String(a):r.map(m).join("");return`${o}${i}</${e}>`}function bn(t){let e=T(void 0);return{body:S(e,()=>m(t)),head:ct(e.head)}}async function _n(t,e={}){let n=t.default||t,r=typeof t.loader=="function"?await t.loader(e):void 0,s=T(r),o=e.params||{};return{body:S(s,()=>m(ot(n,{...o,loaderData:r}))),head:ct(s.head),loaderData:r}}var $t=12;async function Ee(t,e){e||(e=T(void 0));let n="";for(let s=0;s<$t;s++){n=S(e,()=>m(t));let o=[...e.resources.values()].filter(a=>a.status==="pending").map(a=>a.promise);if(o.length===0)break;await Promise.all(o)}let r={};for(let[s,o]of e.resources)o.status==="ready"&&(r[s]=o.value);return{body:n,head:ct(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function J(t,e={},n={}){let r=t.default||t,s=typeof t.loader=="function"?await t.loader(e):void 0,o=T(s),a=e.params||{},{body:i,head:c,resources:u}=await Ee(ot(r,{...a,loaderData:s}),o),d={loaderData:s??null,resources:u,islandStores:St(o)};return Ae({body:i,head:c,payload:d,options:n})}function Ae({body:t,head:e,payload:n,options:r={}}){let s=r.lang||"en",o=`<script id="__what_data" type="application/json">${N(n)}<\/script>`,a=r.clientEntry?`<script type="module" src="${w(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?et(r.csrfToken):"")+(r.head||""),u=r.bodyClass?` class="${w(r.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${w(s)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${e||""}${c}</head><body${u}>${t}${o}${a}</body></html>`}async function*x(t,e){if(e===void 0&&(e=T(void 0)),t==null||t===!1||t===!0)return;if(typeof t=="string"||typeof t=="number"){yield w(String(t));return}if(typeof t=="function"&&t._signal){let a=S(e,()=>t());yield*x(a,e);return}if(typeof t=="function"&&t._mapArray){let a=null;try{a=S(e,()=>it(t))}catch{typeof process<"u"}a&&(yield*x(a,e));return}if(typeof t=="function"){try{let a=S(e,()=>t());yield*x(a,e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let a of t)yield*x(a,e);return}if(ut.has(t.tag))return;if(t.tag==="__errorBoundary"){let a;try{a=S(e,()=>(t.children||[]).map(m).join(""))}catch(i){if(i&&typeof i.then=="function")throw i;a=S(e,()=>m(ft(t,i)))}yield a;return}if(t.tag==="__suspense"){let a=null;for(let i=0;i<$t&&a===null;i++){let c=null;try{a=S(e,()=>(t.children||[]).map(m).join(""))}catch(u){if(u&&typeof u.then=="function")c=u;else throw u}if(a===null){let u=[...e.resources.values()].filter(d=>d.status==="pending").map(d=>d.promise);await Promise.all([c,...u].filter(Boolean))}}a===null&&(a=S(e,()=>m(t.props&&t.props.fallback))),yield a;return}if(typeof t.tag=="function"){let a=at(t.tag);try{let i=S(e,()=>t.tag(dt(t))),c=i instanceof Promise?await i:i;yield*x(c,e)}catch(i){typeof process<"u",yield $?`<!-- SSR Error: ${w(i.message||"Component error")} -->`:"<!-- SSR Error -->"}finally{st(a)}return}let{tag:n,props:r,children:s}=t;pt(n);let o=ht(r||{});if(yield`<${n}${o}>`,!yt.has(n)){let a=lt(r);if(a!=null)yield String(a);else for(let i of s)yield*x(i,e);yield`</${n}>`}}function Rn(t){return{mode:"static",...t}}function En(t,e={}){let n=T(e),r=S(n,()=>m(ot(t.component,e))),s=t.islands||[];return Te({title:t.title||"",meta:t.meta||{},body:r,islands:s,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function Te({title:t,meta:e,body:n,islands:r,scripts:s,styles:o,mode:a}){let i=Object.entries(e).map(([l,p])=>`<meta name="${w(l)}" content="${w(p)}">`).join(`
2
- `),c=o.map(l=>`<link rel="stylesheet" href="${w(l)}">`).join(`
3
- `),u=r.length>0?`
1
+ import{AsyncLocalStorage as ze}from"node:async_hooks";import{__installServerContextStorage as Ge}from"what-core";import{h as at,_isAriaAttr as we,_beginComponentSSR as st,_endComponentSSR as it,_mapArrayToArray as ct,getServerContext as vt,runWithServerContext as S,beginHeadCollection as Se,endHeadCollection as ut}from"what-core";var Lt=new RegExp("[<>&\\u2028\\u2029]","g"),Mt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function N(t){return JSON.stringify(t).replace(Lt,e=>Mt[e.charCodeAt(0)])}import{mount as Ke,hydrate as Ze,signal as Qe,batch as qe,getServerContext as Ft}from"what-core";var Ut=new Map;function Bt(t){let e=t||Ft();return e&&e.islandStores instanceof Map?e.islandStores:null}function bt(t){let e=typeof document<"u"?Ut:Bt(t),r={};for(let[n,s]of e||[])r[n]=s._getSnapshot();return r}import{signal as R,batch as q}from"what-core";var M=Symbol.for("what.revalidationHandler"),_t=!(typeof process<"u");function K(t){globalThis[M]=t}function Jt(){return globalThis[M]??null}async function Z(t,e){let r=globalThis[M];if(r&&r.revalidatePath)return r.revalidatePath(t,e);_t&&console.warn(`[what] revalidatePath('${t}') had no effect: no cache engine is bound. Create a what-isr engine and bind it in your adapter (setRevalidationHandler).`)}async function Q(t,e){let r=globalThis[M];if(r&&r.revalidateTag)return r.revalidateTag(t,e);_t&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var tt=new Map;function Vt(){if(typeof document<"u"){let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);if(e)return decodeURIComponent(e[1])}return null}function et(){if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let t=new Uint8Array(16);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}throw Object.assign(new Error("[what] No secure random source available for CSRF token generation"),{code:"ERR_NO_SECURE_RANDOM"})}function Rt(t,e){if(!t||!e||t.length!==e.length)return!1;let r=0;for(let n=0;n<t.length;n++)r|=t.charCodeAt(n)^e.charCodeAt(n);return r===0}function rt(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}">`}var Wt=0,zt=!1;function Gt(){return!zt&&typeof process<"u",`a_${typeof crypto<"u"&&crypto.getRandomValues?Array.from(crypto.getRandomValues(new Uint8Array(6)),e=>e.toString(16).padStart(2,"0")).join(""):`c${(++Wt).toString(36)}_${Date.now().toString(36)}`}`}function Xt(t,e={}){let r=e.id||Gt(),{onError:n,onSuccess:s,revalidate:a}=e;typeof window>"u"&&tt.set(r,{fn:t,options:e});async function o(...i){if(typeof window>"u")return t(...i);let c=e.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let f=Vt(),l={"Content-Type":"application/json","X-What-Action":r};f&&(l["X-CSRF-Token"]=f);let p=await fetch("/__what_action",{method:"POST",headers:l,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let m=await p.json().catch(()=>({message:"Action failed"}));throw Object.assign(new Error(m.message||"Action failed"),{code:"ERR_ACTION_FAILED"})}let h=await p.json();if(s&&s(h),a)for(let m of a)Tt(m);return h}catch(f){if(f.name==="AbortError"){let l=new Error(`Action "${r}" timed out after ${c}ms`);throw l.code="TIMEOUT",n&&n(l),l}throw n&&n(f),f}finally{clearTimeout(d)}}return o._actionId=r,o._isAction=!0,o}function Et(t,e={}){let{onSuccess:r,onError:n,resetOnSuccess:s=!0}=e;return async a=>{let o,i;a instanceof Event?(a.preventDefault(),i=a.target,o=new FormData(i)):o=a;let c={},u=!1;for(let[d,f]of o.entries())typeof File<"u"&&f instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(f):c[d]=[c[d],f]:c[d]=f;try{let d=u?await t(c,o):await t(c);return r&&r(d,i),s&&i&&i.reset(),d}catch(d){throw n&&n(d,i),d}}}function At(t){let e=R(!1),r=R(null),n=R(null);async function s(...a){e.set(!0),r.set(null);try{let o=await t(...a);return n.set(o),o}catch(o){throw r.set(o),o}finally{e.set(!1)}}return{trigger:s,isPending:()=>e(),error:()=>r(),data:()=>n(),reset:()=>{r.set(null),n.set(null)}}}function Yt(t,e={}){let{resetOnSuccess:r=!0}=e,n={current:null},s=At(Et(t,{resetOnSuccess:r}));function a(o){o.preventDefault();let i=new FormData(o.target);return n.current=o.target,s.trigger(i)}return{...s,handleSubmit:a,formRef:n}}function Kt(t,e){let r=R(t),n=R([]),s=R(t);function a(u){let d=e(r.peek(),u);q(()=>{n.set([...n.peek(),u]),r.set(d)})}function o(u,d){q(()=>{if(n.set(n.peek().filter(f=>f!==u)),d!==void 0){s.set(d);let f=d;for(let l of n.peek())f=e(f,l);r.set(f)}})}function i(u,d){q(()=>{let f=n.peek().filter(h=>h!==u);n.set(f);let l=d!==void 0?d:s.peek();s.set(l);let p=l;for(let h of f)p=e(p,h);r.set(p)})}async function c(u,d){a(u);try{let f=await d();return o(u,f),f}catch(f){throw i(u),f}}return{value:()=>r(),isPending:()=>n().length>0,addOptimistic:a,resolve:o,rollback:i,withOptimistic:c,set:u=>{r.set(u),s.set(u)}}}var j=new Map;function Zt(t,e){return j.has(t)||j.set(t,new Set),j.get(t).add(e),()=>{j.get(t)?.delete(e)}}function Tt(t){let e=j.get(t);if(e)for(let r of e)try{r()}catch(n){console.error("[what] Revalidation error:",n)}}function F(t,e,r,n={}){let{csrfToken:s,skipCsrf:a=!1}=n;if(!a){if(!s)return Promise.resolve({status:500,body:{message:"[what] CSRF token not configured. Pass { csrfToken: sessionToken } to handleActionRequest, or { skipCsrf: true } to explicitly opt out."}});let i=t?.headers?.["x-csrf-token"]||t?.headers?.["X-CSRF-Token"];if(!Rt(i,s))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let o=tt.get(e);return o?Array.isArray(r)?o.fn(...r).then(async i=>{let c=o.options||{};if(Array.isArray(c.revalidate))for(let u of c.revalidate)await Z(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await Q(u);return{status:200,body:i}}).catch(i=>(console.error(`[what] Action "${e}" error:`,i),{status:500,body:{message:"Action failed"}})):Promise.resolve({status:400,body:{message:"Invalid action arguments"}}):Promise.resolve({status:404,body:{message:"Action not found"}})}function Qt(){return[...tt.keys()]}function qt(t,e={}){let{onSuccess:r,onError:n,onSettled:s}=e,a={isPending:R(!1),error:R(null),data:R(null)};async function o(...i){a.isPending.set(!0),a.error.set(null);try{let c=await t(...i);return a.data.set(c),r&&r(c,...i),c}catch(c){throw a.error.set(c),n&&n(c,...i),c}finally{a.isPending.set(!1),s&&s(a.data.peek(),a.error.peek(),...i)}}return{mutate:o,isPending:()=>a.isPending(),error:()=>a.error(),data:()=>a.data(),reset:()=>{a.error.set(null),a.data.set(null)}}}import{h as U}from"what-core";var kt="/__what_action";function te(t){if(typeof t=="string")return t;if(typeof t=="function"){let e=t._actionId;if(e)return e;throw Object.assign(new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string."),{code:"ERR_FORM_ACTION_NOT_REGISTERED"})}throw Object.assign(new Error("[what] <Form> requires an `action` prop: a server action or its id."),{code:"ERR_FORM_ACTION_MISSING"})}function ee(){if(typeof document>"u")return null;let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return e?decodeURIComponent(e[1]):null}function re({action:t,csrfToken:e,redirect:r,method:n="post",enhance:s=!0,children:a,...o}){let i=te(t),c=e!==void 0?e:ee();c==null&&typeof process<"u";let u=[U("input",{type:"hidden",name:"_action",value:i}),U("input",{type:"hidden",name:"what-csrf-token",value:c||""})];r&&u.push(U("input",{type:"hidden",name:"_redirect",value:r}));let d={...o,method:n,action:o.action||kt,"data-action":i};s&&(d["data-enhance"]="");let f=a==null?[]:Array.isArray(a)?a:[a];return U("form",d,...u,...f)}var ne="/__what_action",H=1024*1024;function oe(t){if(!t)return{};if(typeof t.forEach=="function"&&typeof t.get=="function"){let r={};return t.forEach((n,s)=>{r[s.toLowerCase()]=n}),r}let e={};for(let r in t)e[r.toLowerCase()]=t[r];return e}function B(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function nt(t,e){return{status:t,headers:{"content-type":"text/html; charset=utf-8"},body:`<!DOCTYPE html><html><body><h1>${t}</h1><p>${String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}</p></body></html>`}}function Ot(t){if(typeof t!="string"||!t.startsWith("/")||/^[/\\]{2}/.test(t)||t.includes("\\"))return null;try{let e=new URL(t,"http://localhost");return e.origin!=="http://localhost"?null:e.pathname+e.search}catch{return null}}function ae(t,e){let r=Ot(t&&t._redirect);if(r)return r;let n=e.referer||e.referrer;if(n)try{let s=new URL(n,"http://localhost"),a=Ot(s.pathname+s.search);if(a)return a}catch{}return"/"}var se=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function D(t={}){let{getCsrfToken:e,skipCsrf:r=!1}=t;return async function(s){if((s.method||"POST").toUpperCase()!=="POST")return B(405,{message:"Method Not Allowed"});let o=oe(s.headers),i=o["x-what-action"],c=o["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=r?void 0:e?await e(s):void 0;if(u){let h=s.body||{},m=h._action||h["data-action"]||s.query&&s.query.action;if(!m)return nt(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let b={...o},C=h._csrf??h["what-csrf-token"];if(C&&!b["x-csrf-token"]&&(b["x-csrf-token"]=String(C)),!r&&e&&!d)return nt(403,"Missing CSRF token");let v={};for(let[x,G]of Object.entries(h))se.has(x)||(v[x]=G);let O=await F({headers:b},m,[v],{csrfToken:d,skipCsrf:r});return O.status===200?{status:303,headers:{location:ae(h,o)},body:""}:nt(O.status,O.body&&O.body.message||"Action failed")}if(!i)return B(400,{message:"Missing X-What-Action header"});if(!r&&e&&!d)return B(403,{message:"Missing CSRF token"});let l=(s.body||{}).args,p=await F({headers:o},i,l,{csrfToken:d,skipCsrf:r});return B(p.status,p.body)}}function ie(t={}){let e=t.basePath||ne,r=D(t);return async function(s,a,o){let[i,c]=(s.url||"").split("?");if(i!==e||(s.method||"").toUpperCase()!=="POST")return o?o():void 0;let u;try{let l=await ce(s);u=J(l,s.headers["content-type"]||"")}catch(l){a.writeHead(l.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),a.end(JSON.stringify({message:l.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let d=Object.fromEntries(new URLSearchParams(c||"")),f=await r({method:s.method,headers:s.headers,body:u,query:d});a.writeHead(f.status,f.headers),a.end(f.body)}}function J(t,e){if((e||"").includes("application/x-www-form-urlencoded")){let r={};for(let[n,s]of new URLSearchParams(String(t)))r[n]===void 0?r[n]=s:Array.isArray(r[n])?r[n].push(s):r[n]=[r[n],s];return r}return t==null||t===""?{}:JSON.parse(String(t))}async function V(t,e=H){let r=Number(t.headers.get("content-length"));if(Number.isFinite(r)&&r>e)return{tooLarge:!0};let n=t.body;if(!n||typeof n.getReader!="function"){let i=await t.text();return Buffer.byteLength(i,"utf8")>e?{tooLarge:!0}:{raw:i}}let s=n.getReader(),a=[],o=0;for(;;){let{done:i,value:c}=await s.read();if(i)break;if(c){if(o+=c.byteLength,o>e){try{await s.cancel()}catch{}return{tooLarge:!0}}a.push(c)}}return{raw:Buffer.concat(a.map(i=>Buffer.from(i))).toString("utf8")}}function ce(t){return new Promise((e,r)=>{let n=0,s=[];t.on("data",a=>{if(n+=a.length,n>H){let o=new Error("Body too large");o.code="BODY_TOO_LARGE",r(o),t.destroy?.();return}s.push(a)}),t.on("end",()=>{if(s.length===0)return e("");e(Buffer.concat(s).toString("utf8"))}),t.on("error",r)})}function ue(t={}){let e=D(t);return async function(r){let n={};try{let o=await V(r);if(o.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});n=J(o.raw,r.headers.get("content-type")||"")}catch{n={}}let s={};try{s=Object.fromEntries(new URL(r.url,"http://localhost").searchParams)}catch{}let a=await e({method:r.method,headers:r.headers,body:n,query:s});return new Response(a.body,{status:a.status,headers:a.headers})}}import{matchRoute as de,parseQuery as fe}from"what-router/match";var le="/__what_action",pe="/__what_revalidate",ot="what-csrf";function L(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((r,n)=>{e[n.toLowerCase()]=r}),e}function Ct(t,e){if(!t)return null;let r=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return r?decodeURIComponent(r[1]):null}async function he(t){try{let e=await V(t);return e.tooLarge?{tooLarge:!0}:J(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function me(t){let e;try{e=await V(t)}catch{return{json:{}}}if(e.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(e.raw??"")}}catch{return{json:{}}}}function ye(t){return async function(r){let{route:n,params:s,query:a,request:o,csrfToken:i}=r,c={default:n.component,loader:n.loader},u=i?{params:s,query:a,request:o,csrfToken:i}:{params:s,query:a,request:o},d=i?{...t,csrfToken:i}:t;return{html:await W(c,u,d),status:200,tags:r.config&&r.config.tags||[],path:r.path}}}function T(t={}){let{routes:e=[],cache:r,render:n,revalidateWebhook:s,document:a={},notFound:o,basePath:i="",csrf:c=!0}=t,u=c!==!1&&!t.actionHandler,d=t.actionHandler||D(u?{getCsrfToken:l=>Ct(l.headers&&l.headers.cookie,ot)}:{skipCsrf:!0}),f=n||ye(a);return r&&(r.revalidatePath||r.revalidateTag)&&K({revalidatePath:r.revalidatePath,revalidateTag:r.revalidateTag}),async function(p){let h=new URL(p.url,"http://localhost"),m=h.pathname;if(i&&m.startsWith(i)&&(m=m.slice(i.length)||"/"),p.method==="POST"&&m===le){let g=await he(p);if(g&&g.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await d({method:"POST",headers:L(p.headers),body:g,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let b=null,C=null;if(u&&(b=Ct(L(p.headers).cookie,ot),!b)){b=et();let A=L(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;C=`${ot}=${encodeURIComponent(b)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let v=g=>(C&&(g["set-cookie"]=C),g);if(p.method==="POST"&&m===pe&&s){let g=await me(p);if(g.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await s({headers:L(p.headers),body:g.json});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let O=de(m,e);if(!O){let g=o?o():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(g,{status:404,headers:v({"content-type":"text/html; charset=utf-8"})})}let{route:x,params:G}=O,X=x.page||{mode:x.mode||"client"},I={path:m,query:fe(h.search),config:X,route:x,params:G,request:p};if(r&&X.mode!=="server"){I.varyHeaders=L(p.headers);let g=await r.handle(I,()=>f(I));return new Response(g.html,{status:g.status||200,headers:v({"content-type":"text/html; charset=utf-8",...g.headers||{}})})}b&&(I.csrfToken=b);let Y=await f(I),St=v({"content-type":"text/html; charset=utf-8",...Y.headers||{}});return X.mode==="server"&&(St["Cache-Control"]="private, no-store"),new Response(Y.html,{status:Y.status||200,headers:St})}}function ge(t={}){let e=T(t);return{async fetch(r,n,s){return n&&(r.__env=n),s&&(r.__ctx=s),e(r)}}}function k(t){return{head:Se(),loaderData:t,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var xt=0;function be(){xt=0}function _e(){return"h"+xt++}function Re(t){if(!vt()){let e=k(void 0);return S(e,()=>Re(t))}return be(),E(t)}var Pt=new Set(["__errorBoundary","__suspense"]),dt=new Set(["__portal"]);function ft(t){let e=t.children;return!e||e.length===0?{...t.props}:{...t.props,children:e}}function lt(t,e){let r=t.props&&t.props.fallback;if(typeof r!="function")return r;let n=t.props&&t.props.reset||(()=>{});try{return r({error:e,reset:n})}catch(s){return _(s),$&&console.warn(`[what-server] <ErrorBoundary> fallback threw during SSR: ${s.message}`),null}}function E(t){if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return w(String(t));if(typeof t=="function"&&t._signal)return`<!--$-->${E(t())}<!--/$-->`;if(typeof t=="function"&&t._mapArray)try{return`<!--$-->${E(ct(t))}<!--/$-->`}catch(c){return _(c),typeof process<"u","<!--$--><!--/$-->"}if(typeof t=="function")try{return`<!--$-->${E(t())}<!--/$-->`}catch(c){return _(c),typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(E).join("")}<!--/[]-->`;if(dt.has(t.tag))return"";if(Pt.has(t.tag))try{return(t.children||[]).map(E).join("")}catch(c){_(c);let u=c&&typeof c.then=="function";if(u&&t.tag==="__errorBoundary"||!u&&t.tag==="__suspense")throw c;return E(lt(t,u?null:c))}if(typeof t.tag=="function"){let c=_e(),u=st(t.tag),d;try{d=E(t.tag(ft(t)))}finally{it(u)}return Ee(d,c)}let{tag:e,props:r,children:n}=t;ht(e,t);let s=mt(r||{}),a=`<${e}${s}>`;if(yt.has(e))return a;let o=pt(r),i=o!=null?String(o):n.map(E).join("");return`${a}${i}</${e}>`}function Ee(t,e){let r=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(r){let n=r[1],s=r[2],a=n.length+1+s.length,o=t.indexOf(">",a),i=t.slice(a,o===-1?void 0:o);return/[\s"']data-hk\s*=/.test(i)||/^\s*data-hk\s*=/.test(i)?t:t.slice(0,a)+` data-hk="${e}"`+t.slice(a)}return t}function y(t){if(!vt()){let c=k(void 0);return S(c,()=>y(t))}if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return w(String(t));if(typeof t=="function"&&t._signal)return y(t());if(typeof t=="function"&&t._mapArray)try{return y(ct(t))}catch(c){return _(c),typeof process<"u",""}if(typeof t=="function")try{return y(t())}catch(c){return _(c),typeof process<"u",""}if(Array.isArray(t))return t.map(y).join("");if(dt.has(t.tag))return"";if(Pt.has(t.tag))try{return(t.children||[]).map(y).join("")}catch(c){_(c);let u=c&&typeof c.then=="function";if(u&&t.tag==="__errorBoundary"||!u&&t.tag==="__suspense")throw c;return y(lt(t,u?null:c))}if(typeof t.tag=="function"){let c=st(t.tag);try{return y(t.tag(ft(t)))}finally{it(c)}}let{tag:e,props:r,children:n}=t;ht(e,t);let s=mt(r||{}),a=`<${e}${s}>`;if(yt.has(e))return a;let o=pt(r),i=o!=null?String(o):n.map(y).join("");return`${a}${i}</${e}>`}function _r(t){let e=k(void 0);return{body:S(e,()=>y(t)),head:ut(e.head)}}async function Rr(t,e={}){let r=t.default||t,n=typeof t.loader=="function"?await t.loader(e):void 0,s=k(n),a=e.params||{};return{body:S(s,()=>y(at(r,{...a,loaderData:n}))),head:ut(s.head),loaderData:n}}var $t=12;async function Ae(t,e){e||(e=k(void 0));let r="",n=e.resourceCounter;for(let a=0;a<$t;a++){e.resourceCounter=n,r=S(e,()=>y(t));let o=[...e.resources.values()].filter(i=>i.status==="pending").map(i=>i.promise);if(o.length===0)break;await Promise.all(o)}let s={};for(let[a,o]of e.resources)o.status==="ready"&&(s[a]=o.value);return{body:r,head:ut(e.head),loaderData:e.loaderData,resources:s,ctx:e}}async function W(t,e={},r={}){let n=t.default||t,s=typeof t.loader=="function"?await t.loader(e):void 0,a=k(s),o=e.params||{},{body:i,head:c,resources:u}=await Ae(at(n,{...o,loaderData:s}),a),d={loaderData:s??null,resources:u,islandStores:bt(a)};return Te({body:i,head:c,payload:d,options:r})}function Te({body:t,head:e,payload:r,options:n={}}){let s=n.lang||"en",a=`<script id="__what_data" type="application/json">${N(r)}<\/script>`,o=n.clientEntry?`<script type="module" src="${w(n.clientEntry)}"><\/script>`:"",c=(n.csrfToken?rt(n.csrfToken):"")+(n.head||""),u=n.bodyClass?` class="${w(n.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${w(s)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${e||""}${c}</head><body${u}>${t}${a}${o}</body></html>`}async function*P(t,e){if(e===void 0&&(e=k(void 0)),t==null||t===!1||t===!0)return;if(typeof t=="string"||typeof t=="number"){yield w(String(t));return}if(typeof t=="function"&&t._signal){let o=S(e,()=>t());yield*P(o,e);return}if(typeof t=="function"&&t._mapArray){let o=null;try{o=S(e,()=>ct(t))}catch(i){_(i),typeof process<"u"}o&&(yield*P(o,e));return}if(typeof t=="function"){try{let o=S(e,()=>t());yield*P(o,e)}catch(o){_(o),typeof process<"u"}return}if(Array.isArray(t)){for(let o of t)yield*P(o,e);return}if(dt.has(t.tag))return;if(t.tag==="__errorBoundary"){let o;try{o=S(e,()=>(t.children||[]).map(y).join(""))}catch(i){if(_(i),i&&typeof i.then=="function")throw i;o=S(e,()=>y(lt(t,i)))}yield o;return}if(t.tag==="__suspense"){let o=null,i=e.resourceCounter;for(let c=0;c<$t&&o===null;c++){e.resourceCounter=i;let u=null;try{o=S(e,()=>(t.children||[]).map(y).join(""))}catch(d){if(d&&typeof d.then=="function")u=d;else throw d}if(o===null){let d=[...e.resources.values()].filter(f=>f.status==="pending").map(f=>f.promise);await Promise.all([u,...d].filter(Boolean))}}o===null&&(o=S(e,()=>y(t.props&&t.props.fallback))),yield o;return}if(typeof t.tag=="function"){let o=st(t.tag);try{let i=S(e,()=>t.tag(ft(t))),c=i instanceof Promise?await i:i;yield*P(c,e)}catch(i){_(i),typeof process<"u",yield $?`<!-- SSR Error: ${w(i.message||"Component error")} -->`:"<!-- SSR Error -->"}finally{it(o)}return}let{tag:r,props:n,children:s}=t;ht(r,t);let a=mt(n||{});if(yield`<${r}${a}>`,!yt.has(r)){let o=pt(n);if(o!=null)yield String(o);else for(let i of s)yield*P(i,e);yield`</${r}>`}}function Er(t){return{mode:"static",...t}}function Ar(t,e={}){let r=k(e),n=S(r,()=>y(at(t.component,e))),s=t.islands||[];return ke({title:t.title||"",meta:t.meta||{},body:n,islands:s,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function ke({title:t,meta:e,body:r,islands:n,scripts:s,styles:a,mode:o}){let i=Object.entries(e).map(([l,p])=>`<meta name="${w(l)}" content="${w(p)}">`).join(`
2
+ `),c=a.map(l=>`<link rel="stylesheet" href="${w(l)}">`).join(`
3
+ `),u=n.length>0?`
4
4
  <script type="module">
5
5
  import { hydrateIslands } from '/@what/islands.js';
6
6
  hydrateIslands();
7
7
  <\/script>`:"",d=s.map(l=>`<script type="module" src="${w(l)}"><\/script>`).join(`
8
- `),f=a==="client"?`
8
+ `),f=o==="client"?`
9
9
  <script type="module" src="/@what/client.js"><\/script>`:"";return`<!DOCTYPE html>
10
10
  <html lang="en">
11
11
  <head>
@@ -16,9 +16,9 @@ import{AsyncLocalStorage as Je}from"node:async_hooks";import{__installServerCont
16
16
  ${c}
17
17
  </head>
18
18
  <body>
19
- <div id="app">${n}</div>
19
+ <div id="app">${r}</div>
20
20
  ${u}
21
21
  ${d}
22
22
  ${f}
23
23
  </body>
24
- </html>`}function An(t){return t._server=!0,t}var $=!(typeof process<"u");function lt(t){return t?t.dangerouslySetInnerHTML?t.dangerouslySetInnerHTML.__html??null:t.innerHTML&&typeof t.innerHTML=="object"&&"__html"in t.innerHTML?t.innerHTML.__html??null:(t.innerHTML!=null&&typeof t.innerHTML=="string"&&$&&console.warn("[what-server] innerHTML received a raw string. This is a security risk (XSS). Use innerHTML={{ __html: trustedString }} or dangerouslySetInnerHTML={{ __html: trustedString }} instead."),null):null}var ke=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,Oe=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function pt(t){if(typeof t!="string"||!Oe.test(t))throw Object.assign(new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(t)}`),{code:"ERR_INVALID_SSR_TAG"})}function ht(t){let e="";for(let[n,r]of Object.entries(t)){if(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")continue;let s=n.toLowerCase();if(s.startsWith("on")&&n.length>2)continue;let o=r;if(typeof o=="function"){try{o=o()}catch(a){$&&console.warn(`[what-server] Skipping attribute ${JSON.stringify(n)}: its value threw during SSR: ${a.message}`);continue}if(typeof o=="function")continue}if(o===!1&&ge(n)){e+=` ${n}="false"`;continue}if(!(o===!1||o==null)){if(!ke.test(n)){$&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(xe.has(s)){$&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")e+=` class="${w(String(o))}"`;else if(n==="style"&&typeof o=="object"){let a=Object.entries(o).map(([i,c])=>`${$e(i)}:${c}`).join(";");e+=` style="${w(a)}"`}else if(o===!0)n.startsWith("aria-")||n==="role"?e+=` ${n}="true"`:e+=` ${n}`;else{if(Ce(n,o))continue;e+=` ${n}="${w(String(o))}"`}}}return e}function Ce(t,e){let n=t.toLowerCase();if(!ve.has(n))return!1;let r=String(e).trim().replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();return r.startsWith("javascript:")||r.startsWith("vbscript:")||r.startsWith("data:")}var ve=new Set(["href","src","action","formaction","data","ping","xlink:href"]),xe=new Set(["srcdoc"]);function w(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function $e(t){return t.startsWith("--")?t:t.replace(/([A-Z])/g,"-$1").toLowerCase()}var yt=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);import Pe from"node:http";var mt=Symbol("what.bodyTooLarge"),Pt=()=>new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});async function Nt(t){let n=`http://${t.headers.host||"localhost"}${t.url}`,r=new Headers;for(let[o,a]of Object.entries(t.headers))a!=null&&r.set(o,Array.isArray(a)?a.join(", "):String(a));let s;if(t.method!=="GET"&&t.method!=="HEAD"){let o=Number(t.headers["content-length"]),a=Number.isFinite(o)&&o>j,i=[],c=0;for await(let u of t)if(!a){if(c+=u.length,c>j){a=!0,i.length=0;continue}i.push(u)}if(a)return mt;i.length&&(s=Buffer.concat(i))}return new Request(n,{method:t.method,headers:r,body:s})}async function W(t,e){t.statusCode=e.status,e.headers.forEach((r,s)=>t.setHeader(s,r));let n=await e.text();t.end(n)}function It(t){return async function(n,r){try{let s=await Nt(n);if(s===mt)return await W(r,Pt());let o=await t(s);await W(r,o)}catch(s){r.headersSent||r.writeHead(500,{"content-type":"text/html; charset=utf-8"}),r.end("<!DOCTYPE html><html><body><h1>500 \u2014 Server Error</h1></body></html>"),console.error("[what-server] request error:",s)}}}function Ne(t={}){let e=A(t);return async function(r,s,o){let a=await Nt(r);if(a===mt)return await W(s,Pt());let i=await e(a);if(i.status===404&&typeof o=="function")return o();await W(s,i)}}function Ie(t={}){let e=A(t),n=Pe.createServer(It(e)),{scheduler:r}=t;if(r){r.start();let s=()=>{try{r.stop()}catch{}n.close()};process.once("SIGTERM",s),process.once("SIGINT",s)}return n}import{mkdir as je,writeFile as jt}from"node:fs/promises";import{join as gt,resolve as Ht,sep as He}from"node:path";import{matchRoute as De}from"what-router/match";function Le(t){return t.includes(":")||t.includes("*")||t.includes("[")}function Me(t,e){return t.replace(/\[\.\.\.(\w+)\]/g,(n,r)=>e[r]??"").replace(/\[(\w+)\]/g,(n,r)=>e[r]??"").replace(/[:*](\w+)/g,(n,r)=>e[r]??"")}function Fe(t,e){let n=Ht(t),r=Ht(gt(t,e==="/"?"":e));if(r!==n&&!r.startsWith(n+He))throw Object.assign(new Error(`[what-server] Refusing to write outside outDir: ${e}`),{code:"ERR_STATIC_WRITE_ESCAPE"});return r}async function Ue({routes:t=[],outDir:e,render:n,documentOptions:r={}}={}){let s=[];for(let o of t){let a=o.page&&o.page.mode||o.mode;if(a!=="static"&&a!=="hybrid")continue;let i={default:o.component,loader:o.loader},c=[o.path];if(Le(o.path)){if(typeof o.getStaticPaths!="function")continue;c=((await o.getStaticPaths()).paths||[]).map(d=>Me(o.path,d.params||{}))}for(let u of c){let d=Fe(e,u),f=De(u,[o]),p={params:f?f.params:{},query:{}},h=n?await n(i,p):await J(i,p,r);if(await je(d,{recursive:!0}),await jt(gt(d,"index.html"),h),typeof o.loader=="function"){let y=await o.loader(p);await jt(gt(d,"__what_data.json"),N({loaderData:y}))}s.push(u)}}return{pages:s}}function Be(t={}){return A(t)}async function Ve({outDir:t=".vercel/output",functionName:e="render",runtime:n="nodejs22.x",files:r=null,handler:s="index.mjs",staticDir:o=null}={}){let{mkdir:a,writeFile:i,cp:c}=await import("node:fs/promises"),{join:u,dirname:d}=await import("node:path");await a(t,{recursive:!0});let f={version:3,routes:[{handle:"filesystem"},{src:"/.*",dest:`/${e}`}]};await i(u(t,"config.json"),JSON.stringify(f,null,2)),o&&await c(o,u(t,"static"),{recursive:!0});let l=null;if(r&&typeof r=="object"){l=u(t,"functions",`${e}.func`),await a(l,{recursive:!0});let p={runtime:n,handler:s,launcherType:"Nodejs",shouldAddHelpers:!1,supportsResponseStreaming:!0};await i(u(l,".vc-config.json"),JSON.stringify(p,null,2));for(let[h,y]of Object.entries(r)){let b=u(l,h);await a(d(b),{recursive:!0}),await i(b,y)}s in r||console.warn(`[what-server] buildVercelOutput: files does not include the handler entry "${s}" \u2014 the deploy will 500 until your build emits it.`)}return{config:f,outDir:t,functionDir:l}}We(new Je);export{Tt as ACTION_ENDPOINT,ee as Form,Gt as action,Ve as buildVercelOutput,H as createActionHandler,me as createCloudflareHandler,A as createRequestHandler,Ie as createServer,Be as createVercelHandler,et as csrfMetaTag,Rn as definePage,Ue as exportStatic,ce as fetchActionHandler,Rt as formAction,tt as generateCsrfToken,En as generateStaticPage,Zt as getRegisteredActions,Bt as getRevalidationHandler,M as handleActionRequest,At as invalidatePath,se as nodeActionMiddleware,Kt as onRevalidate,J as renderDocument,_n as renderPage,_e as renderToHydratableString,x as renderToStream,m as renderToString,Ee as renderToStringAsync,bn as renderToStringWithHead,K as revalidatePath,Z as revalidateTag,N as serializeState,An as server,X as setRevalidationHandler,It as toNodeListener,Et as useAction,Yt as useFormAction,Qt as useMutation,Xt as useOptimistic,_t as validateCsrfToken,Ne as whatMiddleware};
24
+ </html>`}function Tr(t){return t._server=!0,t}var $=!(typeof process<"u");function pt(t){return t?t.dangerouslySetInnerHTML?t.dangerouslySetInnerHTML.__html??null:t.innerHTML&&typeof t.innerHTML=="object"&&"__html"in t.innerHTML?t.innerHTML.__html??null:(t.innerHTML!=null&&typeof t.innerHTML=="string"&&$&&console.warn("[what-server] innerHTML received a raw string. This is a security risk (XSS). Use innerHTML={{ __html: trustedString }} or dangerouslySetInnerHTML={{ __html: trustedString }} instead."),null):null}var Oe=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,Ce=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function _(t){if(t&&t.code==="ERR_COMPILED_JSX_IN_SSR")throw t}function ve(t){return!!t&&typeof t=="object"&&typeof t.nodeType=="number"}function ht(t,e){if(!(typeof t=="string"&&Ce.test(t)))throw ve(e)?Object.assign(new Error('[what-server] Cannot server-render a DOM node. A component compiled by what-compiler returns a cloned template (finished DOM), not a vnode, so it has no server-rendered form. Author server-rendered views with h(), or compile them with the automatic JSX runtime (jsxImportSource: "what-framework") instead of what-compiler.'),{code:"ERR_COMPILED_JSX_IN_SSR"}):Object.assign(new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(t)}`),{code:"ERR_INVALID_SSR_TAG"})}function mt(t){let e="";for(let[r,n]of Object.entries(t)){if(r==="key"||r==="ref"||r==="children"||r==="dangerouslySetInnerHTML"||r==="innerHTML")continue;let s=r.toLowerCase();if(s.startsWith("on")&&r.length>2)continue;let a=n;if(typeof a=="function"){try{a=a()}catch(o){$&&console.warn(`[what-server] Skipping attribute ${JSON.stringify(r)}: its value threw during SSR: ${o.message}`);continue}if(typeof a=="function")continue}if(a===!1&&(we(r)||r.startsWith("data-"))){e+=` ${r}="false"`;continue}if(!(a===!1||a==null)){if(!Oe.test(r)){$&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(r)}`);continue}if($e.has(s)){$&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(r)}`);continue}if(r==="className"||r==="class")e+=` class="${w(String(a))}"`;else if(r==="style"&&typeof a=="object"){let o=Object.entries(a).map(([i,c])=>`${Ie(i)}:${c}`).join(";");e+=` style="${w(o)}"`}else if(a===!0)r.startsWith("aria-")||r==="role"||r.startsWith("data-")?e+=` ${r}="true"`:e+=` ${r}`;else{if(xe(r,a))continue;e+=` ${r}="${w(String(a))}"`}}}return e}function xe(t,e){let r=t.toLowerCase();if(!Pe.has(r))return!1;let n=String(e).trim().replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();return n.startsWith("javascript:")||n.startsWith("vbscript:")||n.startsWith("data:")}var Pe=new Set(["href","src","action","formaction","data","ping","xlink:href"]),$e=new Set(["srcdoc"]);function w(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function Ie(t){return t.startsWith("--")?t:t.replace(/([A-Z])/g,"-$1").toLowerCase()}var yt=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);import Ne from"node:http";var gt=Symbol("what.bodyTooLarge"),It=()=>new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});async function Nt(t){let r=`http://${t.headers.host||"localhost"}${t.url}`,n=new Headers;for(let[a,o]of Object.entries(t.headers))o!=null&&n.set(a,Array.isArray(o)?o.join(", "):String(o));let s;if(t.method!=="GET"&&t.method!=="HEAD"){let a=Number(t.headers["content-length"]),o=Number.isFinite(a)&&a>H,i=[],c=0;for await(let u of t)if(!o){if(c+=u.length,c>H){o=!0,i.length=0;continue}i.push(u)}if(o)return gt;i.length&&(s=Buffer.concat(i))}return new Request(r,{method:t.method,headers:n,body:s})}async function z(t,e){t.statusCode=e.status,e.headers.forEach((n,s)=>t.setHeader(s,n));let r=await e.text();t.end(r)}function jt(t){return async function(r,n){try{let s=await Nt(r);if(s===gt)return await z(n,It());let a=await t(s);await z(n,a)}catch(s){n.headersSent||n.writeHead(500,{"content-type":"text/html; charset=utf-8"}),n.end("<!DOCTYPE html><html><body><h1>500 \u2014 Server Error</h1></body></html>"),console.error("[what-server] request error:",s)}}}function je(t={}){let e=T(t);return async function(n,s,a){let o=await Nt(n);if(o===gt)return await z(s,It());let i=await e(o);if(i.status===404&&typeof a=="function")return a();await z(s,i)}}function He(t={}){let e=T(t),r=Ne.createServer(jt(e)),{scheduler:n}=t;if(n){n.start();let s=()=>{try{n.stop()}catch{}r.close()};process.once("SIGTERM",s),process.once("SIGINT",s)}return r}import{mkdir as De,writeFile as Ht}from"node:fs/promises";import{join as wt,resolve as Dt,sep as Le}from"node:path";import{matchRoute as Me}from"what-router/match";function Fe(t){return t.includes(":")||t.includes("*")||t.includes("[")}function Ue(t,e){return t.replace(/\[\.\.\.(\w+)\]/g,(r,n)=>e[n]??"").replace(/\[(\w+)\]/g,(r,n)=>e[n]??"").replace(/[:*](\w+)/g,(r,n)=>e[n]??"")}function Be(t,e){let r=Dt(t),n=Dt(wt(t,e==="/"?"":e));if(n!==r&&!n.startsWith(r+Le))throw Object.assign(new Error(`[what-server] Refusing to write outside outDir: ${e}`),{code:"ERR_STATIC_WRITE_ESCAPE"});return n}async function Je({routes:t=[],outDir:e,render:r,documentOptions:n={}}={}){let s=[];for(let a of t){let o=a.page&&a.page.mode||a.mode;if(o!=="static"&&o!=="hybrid")continue;let i={default:a.component,loader:a.loader},c=[a.path];if(Fe(a.path)){if(typeof a.getStaticPaths!="function")continue;c=((await a.getStaticPaths()).paths||[]).map(d=>Ue(a.path,d.params||{}))}for(let u of c){let d=Be(e,u),f=Me(u,[a]),p={params:f?f.params:{},query:{}},h=r?await r(i,p):await W(i,p,n);if(await De(d,{recursive:!0}),await Ht(wt(d,"index.html"),h),typeof a.loader=="function"){let m=await a.loader(p);await Ht(wt(d,"__what_data.json"),N({loaderData:m}))}s.push(u)}}return{pages:s}}function Ve(t={}){return T(t)}async function We({outDir:t=".vercel/output",functionName:e="render",runtime:r="nodejs22.x",files:n=null,handler:s="index.mjs",staticDir:a=null}={}){let{mkdir:o,writeFile:i,cp:c}=await import("node:fs/promises"),{join:u,dirname:d}=await import("node:path");await o(t,{recursive:!0});let f={version:3,routes:[{handle:"filesystem"},{src:"/.*",dest:`/${e}`}]};await i(u(t,"config.json"),JSON.stringify(f,null,2)),a&&await c(a,u(t,"static"),{recursive:!0});let l=null;if(n&&typeof n=="object"){l=u(t,"functions",`${e}.func`),await o(l,{recursive:!0});let p={runtime:r,handler:s,launcherType:"Nodejs",shouldAddHelpers:!1,supportsResponseStreaming:!0};await i(u(l,".vc-config.json"),JSON.stringify(p,null,2));for(let[h,m]of Object.entries(n)){let b=u(l,h);await o(d(b),{recursive:!0}),await i(b,m)}s in n||console.warn(`[what-server] buildVercelOutput: files does not include the handler entry "${s}" \u2014 the deploy will 500 until your build emits it.`)}return{config:f,outDir:t,functionDir:l}}Ge(new ze);export{kt as ACTION_ENDPOINT,re as Form,Xt as action,We as buildVercelOutput,D as createActionHandler,ge as createCloudflareHandler,T as createRequestHandler,He as createServer,Ve as createVercelHandler,rt as csrfMetaTag,Er as definePage,Je as exportStatic,ue as fetchActionHandler,Et as formAction,et as generateCsrfToken,Ar as generateStaticPage,Qt as getRegisteredActions,Jt as getRevalidationHandler,F as handleActionRequest,Tt as invalidatePath,ie as nodeActionMiddleware,Zt as onRevalidate,W as renderDocument,Rr as renderPage,Re as renderToHydratableString,P as renderToStream,y as renderToString,Ae as renderToStringAsync,_r as renderToStringWithHead,Z as revalidatePath,Q as revalidateTag,N as serializeState,Tr as server,K as setRevalidationHandler,jt as toNodeListener,At as useAction,Yt as useFormAction,qt as useMutation,Kt as useOptimistic,Rt as validateCsrfToken,je as whatMiddleware};
package/index.d.ts CHANGED
@@ -4,11 +4,19 @@ import { VNode, VNodeChild, Signal } from 'what-core';
4
4
 
5
5
  // --- SSR ---
6
6
 
7
+ // Every entry point below takes `VNode<any>`, not `VNode`. The `any` is
8
+ // load-bearing, and RouteDefinition.component further down carries the full
9
+ // explanation: `VNode<P>` is effectively invariant in P, so `VNode<{ name: string }>`
10
+ // (what `h(Greeting, { name: 'Alice' })` returns) is NOT assignable to bare
11
+ // `VNode` = `VNode<Record<string, any>>`. Writing `VNode` here made the docs'
12
+ // own first SSR example a TS2345 for every strict consumer. `mount`/`hydrate`
13
+ // never had the problem because they take `VNodeChild`.
14
+
7
15
  /** Render VNode tree to HTML string */
8
- export function renderToString(vnode: VNode): string;
16
+ export function renderToString(vnode: VNode<any>): string;
9
17
 
10
18
  /** Render VNode tree as async iterator for streaming */
11
- export function renderToStream(vnode: VNode): AsyncGenerator<string>;
19
+ export function renderToStream(vnode: VNode<any>): AsyncGenerator<string>;
12
20
 
13
21
  export interface RenderRequestContext {
14
22
  params?: Record<string, string>;
@@ -26,7 +34,7 @@ export interface RenderRequestContext {
26
34
 
27
35
  /** Run a page module's loader, then render it. Returns the body, head and loader data. */
28
36
  export function renderPage(
29
- pageModule: { default: (props: any) => VNode; loader?: (ctx: RenderRequestContext) => any } | ((props: any) => VNode),
37
+ pageModule: { default: (props: any) => VNode<any>; loader?: (ctx: RenderRequestContext) => any } | ((props: any) => VNode<any>),
30
38
  reqCtx?: RenderRequestContext,
31
39
  ): Promise<{ body: string; head: string; loaderData: any }>;
32
40
 
@@ -40,7 +48,7 @@ export interface PageConfig {
40
48
  /** Meta tags */
41
49
  meta?: Record<string, string>;
42
50
  /** Page component */
43
- component: (data?: any) => VNode;
51
+ component: (data?: any) => VNode<any>;
44
52
  /** Islands to hydrate */
45
53
  islands?: string[];
46
54
  /** Scripts to load */
@@ -55,7 +63,7 @@ export function definePage(config: Partial<PageConfig>): PageConfig;
55
63
  export function generateStaticPage(page: PageConfig, data?: any): string;
56
64
 
57
65
  /** Mark component as server-only (no client JS) */
58
- export function server<P>(component: (props: P) => VNode): (props: P) => VNode;
66
+ export function server<P>(component: (props: P) => VNode<any>): (props: P) => VNode<any>;
59
67
 
60
68
  // --- Islands ---
61
69
  //
@@ -193,17 +201,17 @@ export function getRegisteredActions(): string[];
193
201
  * Render with hydration markers (data-hk attributes and comment boundaries) so
194
202
  * the client can adopt the server DOM instead of recreating it.
195
203
  */
196
- export function renderToHydratableString(vnode: VNode): string;
204
+ export function renderToHydratableString(vnode: VNode<any>): string;
197
205
 
198
206
  /** Render, and return the <head> tags collected during that render alongside the body. */
199
- export function renderToStringWithHead(vnode: VNode): { body: string; head: string };
207
+ export function renderToStringWithHead(vnode: VNode<any>): { body: string; head: string };
200
208
 
201
209
  /**
202
210
  * Render, awaiting any suspended resources so their data is resolved in the
203
211
  * output. `resources` is the payload the client reuses so it does not refetch.
204
212
  */
205
213
  export function renderToStringAsync(
206
- vnode: VNode,
214
+ vnode: VNode<any>,
207
215
  ctx?: unknown,
208
216
  ): Promise<{ body: string; head: string; resources: Record<string, unknown> }>;
209
217
 
@@ -229,7 +237,7 @@ export interface DocumentOptions {
229
237
  * component, collects head tags, and inlines the hydration payload.
230
238
  */
231
239
  export function renderDocument(
232
- pageModule: { default: (props: any) => VNode; loader?: (ctx: RenderRequestContext) => any } | ((props: any) => VNode),
240
+ pageModule: { default: (props: any) => VNode<any>; loader?: (ctx: RenderRequestContext) => any } | ((props: any) => VNode<any>),
233
241
  reqCtx?: RenderRequestContext,
234
242
  options?: DocumentOptions,
235
243
  ): Promise<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "what-server",
3
- "version": "0.13.3",
3
+ "version": "0.13.5",
4
4
  "description": "What Framework - SSR, islands architecture, static generation",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -51,8 +51,8 @@
51
51
  "author": "ZVN DEV (https://zvndev.com)",
52
52
  "license": "MIT",
53
53
  "peerDependencies": {
54
- "what-core": "^0.13.3",
55
- "what-router": "^0.13.3"
54
+ "what-core": "^0.13.5",
55
+ "what-router": "^0.13.5"
56
56
  },
57
57
  "peerDependenciesMeta": {
58
58
  "what-router": {
@@ -160,7 +160,9 @@ export function createRequestHandler(options = {}) {
160
160
 
161
161
  // CSRF provisioning for HTML responses (double-submit cookie). If the
162
162
  // visitor has no token cookie yet, mint one and Set-Cookie it below.
163
+ /** @type {string | null} */
163
164
  let csrfToken = null;
165
+ /** @type {string | null} */
164
166
  let csrfSetCookie = null;
165
167
  if (autoCsrf) {
166
168
  csrfToken = readCookie(headersToObject(request.headers).cookie, CSRF_COOKIE);
@@ -66,6 +66,7 @@ export async function buildVercelOutput({
66
66
  await cp(staticDir, join(outDir, 'static'), { recursive: true });
67
67
  }
68
68
 
69
+ /** @type {string | null} */
69
70
  let functionDir = null;
70
71
  if (files && typeof files === 'object') {
71
72
  functionDir = join(outDir, 'functions', `${functionName}.func`);
package/src/index.js CHANGED
@@ -142,6 +142,7 @@ function _boundaryFallback(vnode, error) {
142
142
  try {
143
143
  return fallback({ error, reset });
144
144
  } catch (e) {
145
+ _rethrowIfUnrenderable(e);
145
146
  if (_isDevMode) {
146
147
  console.warn(`[what-server] <ErrorBoundary> fallback threw during SSR: ${e.message}`);
147
148
  }
@@ -169,6 +170,7 @@ function _renderHydratable(vnode) {
169
170
  try {
170
171
  return `<!--$-->${_renderHydratable(_mapArrayToArray(vnode))}<!--/$-->`;
171
172
  } catch (e) {
173
+ _rethrowIfUnrenderable(e);
172
174
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
173
175
  console.warn('[what-server] Error rendering keyed list in SSR:', e.message);
174
176
  }
@@ -181,6 +183,7 @@ function _renderHydratable(vnode) {
181
183
  try {
182
184
  return `<!--$-->${_renderHydratable(vnode())}<!--/$-->`;
183
185
  } catch (e) {
186
+ _rethrowIfUnrenderable(e);
184
187
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
185
188
  console.warn('[what-server] Error rendering reactive function in SSR:', e.message);
186
189
  }
@@ -200,6 +203,7 @@ function _renderHydratable(vnode) {
200
203
  try {
201
204
  return (vnode.children || []).map(_renderHydratable).join('');
202
205
  } catch (e) {
206
+ _rethrowIfUnrenderable(e);
203
207
  const suspended = e && typeof e.then === 'function';
204
208
  if (suspended && vnode.tag === '__errorBoundary') throw e; // belongs to <Suspense>
205
209
  if (!suspended && vnode.tag === '__suspense') throw e; // belongs to <ErrorBoundary>
@@ -223,7 +227,7 @@ function _renderHydratable(vnode) {
223
227
 
224
228
  // Element
225
229
  const { tag, props, children } = vnode;
226
- assertSafeTag(tag);
230
+ assertSafeTag(tag, vnode);
227
231
  const attrs = renderAttrs(props || {});
228
232
  const open = `<${tag}${attrs}>`;
229
233
 
@@ -288,6 +292,7 @@ export function renderToString(vnode) {
288
292
  try {
289
293
  return renderToString(_mapArrayToArray(vnode));
290
294
  } catch (e) {
295
+ _rethrowIfUnrenderable(e);
291
296
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
292
297
  console.warn('[what-server] Error rendering keyed list in SSR:', e.message);
293
298
  }
@@ -300,6 +305,7 @@ export function renderToString(vnode) {
300
305
  try {
301
306
  return renderToString(vnode());
302
307
  } catch (e) {
308
+ _rethrowIfUnrenderable(e);
303
309
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
304
310
  console.warn('[what-server] Error rendering reactive function in SSR:', e.message);
305
311
  }
@@ -328,6 +334,7 @@ export function renderToString(vnode) {
328
334
  try {
329
335
  return (vnode.children || []).map(renderToString).join('');
330
336
  } catch (e) {
337
+ _rethrowIfUnrenderable(e);
331
338
  const suspended = e && typeof e.then === 'function';
332
339
  if (suspended && vnode.tag === '__errorBoundary') throw e; // belongs to <Suspense>
333
340
  if (!suspended && vnode.tag === '__suspense') throw e; // belongs to <ErrorBoundary>
@@ -352,7 +359,7 @@ export function renderToString(vnode) {
352
359
 
353
360
  // Element
354
361
  const { tag, props, children } = vnode;
355
- assertSafeTag(tag);
362
+ assertSafeTag(tag, vnode);
356
363
  const attrs = renderAttrs(props || {});
357
364
  const open = `<${tag}${attrs}>`;
358
365
 
@@ -406,7 +413,15 @@ const MAX_RESOLVE_PASSES = 12;
406
413
  export async function renderToStringAsync(vnode, ctx) {
407
414
  if (!ctx) ctx = createRenderContext(undefined);
408
415
  let body = '';
416
+ // Every pass re-renders the same tree, so every pass must hand out the same
417
+ // resource keys. createResource names a keyless resource `__r${counter++}`
418
+ // off the render context; without restoring the counter, pass 1 asks for
419
+ // `__r1` where pass 0 stored `__r0`, finds nothing cached, and starts the
420
+ // fetch again. The loop then burns all twelve passes, pays for twelve
421
+ // sequential fetches, and returns the Suspense fallback as final HTML.
422
+ const counterAtStart = ctx.resourceCounter;
409
423
  for (let pass = 0; pass < MAX_RESOLVE_PASSES; pass++) {
424
+ ctx.resourceCounter = counterAtStart;
410
425
  body = runWithServerContext(ctx, () => renderToString(vnode));
411
426
  const pending = [...ctx.resources.values()]
412
427
  .filter((r) => r.status === 'pending')
@@ -491,10 +506,12 @@ export async function* renderToStream(vnode, ctx) {
491
506
 
492
507
  // Compiled keyed list: see _renderHydratable above.
493
508
  if (typeof vnode === 'function' && vnode._mapArray) {
509
+ /** @type {any} */
494
510
  let rows = null;
495
511
  try {
496
512
  rows = runWithServerContext(ctx, () => _mapArrayToArray(vnode));
497
513
  } catch (e) {
514
+ _rethrowIfUnrenderable(e);
498
515
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
499
516
  console.warn('[what-server] Error rendering keyed list in stream SSR:', e.message);
500
517
  }
@@ -509,6 +526,7 @@ export async function* renderToStream(vnode, ctx) {
509
526
  const value = runWithServerContext(ctx, () => vnode());
510
527
  yield* renderToStream(value, ctx);
511
528
  } catch (e) {
529
+ _rethrowIfUnrenderable(e);
512
530
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
513
531
  console.warn('[what-server] Error rendering reactive function in stream SSR:', e.message);
514
532
  }
@@ -534,6 +552,7 @@ export async function* renderToStream(vnode, ctx) {
534
552
  try {
535
553
  html = runWithServerContext(ctx, () => (vnode.children || []).map(renderToString).join(''));
536
554
  } catch (e) {
555
+ _rethrowIfUnrenderable(e);
537
556
  if (e && typeof e.then === 'function') throw e; // suspended; belongs to <Suspense>
538
557
  html = runWithServerContext(ctx, () => renderToString(_boundaryFallback(vnode, e)));
539
558
  }
@@ -546,7 +565,13 @@ export async function* renderToStream(vnode, ctx) {
546
565
  // enhancement.) The synchronous render runs inside the threaded ctx.
547
566
  if (vnode.tag === '__suspense') {
548
567
  let html = null;
568
+ // Restored, not zeroed: the counter is context-wide and earlier siblings
569
+ // have already taken keys from it. Resetting to zero would re-issue those
570
+ // keys inside this boundary and render a sibling's data here. See the note
571
+ // in renderToStringAsync for what the missing restore cost.
572
+ const counterAtStart = ctx.resourceCounter;
549
573
  for (let attempt = 0; attempt < MAX_RESOLVE_PASSES && html === null; attempt++) {
574
+ ctx.resourceCounter = counterAtStart;
550
575
  let suspended = null;
551
576
  try {
552
577
  html = runWithServerContext(ctx, () => (vnode.children || []).map(renderToString).join(''));
@@ -580,6 +605,7 @@ export async function* renderToStream(vnode, ctx) {
580
605
  const resolved = result instanceof Promise ? await result : result;
581
606
  yield* renderToStream(resolved, ctx);
582
607
  } catch (e) {
608
+ _rethrowIfUnrenderable(e);
583
609
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
584
610
  console.warn('[what-server] Error rendering component in stream SSR:', e.message);
585
611
  }
@@ -593,7 +619,7 @@ export async function* renderToStream(vnode, ctx) {
593
619
  }
594
620
 
595
621
  const { tag, props, children } = vnode;
596
- assertSafeTag(tag);
622
+ assertSafeTag(tag, vnode);
597
623
  const attrs = renderAttrs(props || {});
598
624
  yield `<${tag}${attrs}>`;
599
625
 
@@ -752,14 +778,74 @@ const SAFE_ATTR_NAME = /^[a-zA-Z_:][a-zA-Z0-9:._-]*$/;
752
778
  // '__suspense' marker tag.
753
779
  const SAFE_TAG_NAME = /^[a-zA-Z_][a-zA-Z0-9._:-]*$/;
754
780
 
755
- function assertSafeTag(tag) {
756
- if (typeof tag !== 'string' || !SAFE_TAG_NAME.test(tag)) {
757
- // ERROR_CODES.INVALID_SSR_TAG
781
+ // A real DOM node reaching a renderer is not a bad tag name, it is a compiled
782
+ // component body.
783
+ //
784
+ // what-compiler lowers a component's own JSX to a module-scope `_$template()`
785
+ // and a `cloneNode(true)` at call time, so the component RETURNS finished DOM
786
+ // rather than a vnode. Every renderer here destructures `vnode.tag`, gets
787
+ // `undefined` off an Element, and used to report ERR_INVALID_SSR_TAG: "Invalid
788
+ // tag name in SSR: undefined". That message names the wrong thing entirely.
789
+ // It sent people looking for a typo'd tag or a component returning a plain
790
+ // object, when the actual cause is that what-compiler's fine-grained output is
791
+ // client-only and there is no supported way to server-render it.
792
+ //
793
+ // This only fires when a DOM implementation exists in the process (jsdom in a
794
+ // test, a shim someone installed). On a bare Node server the compiled module
795
+ // cannot even be IMPORTED — `_$template()` runs at module scope and throws
796
+ // `ReferenceError: document is not defined` first — which is why the build-time
797
+ // guard in what-compiler's Vite plugin is the earlier and better seam. This is
798
+ // the backstop for the paths that get past it.
799
+ // ERR_COMPILED_JSX_IN_SSR must never be swallowed.
800
+ //
801
+ // Every render path here degrades rather than 500s: a reactive child that throws
802
+ // becomes an empty region, a keyed list becomes an empty container, a streamed
803
+ // component becomes `<!-- SSR Error -->`, and an <ErrorBoundary> renders its
804
+ // fallback. That is right for a RUNTIME error — bad data in one row should not
805
+ // take down the page.
806
+ //
807
+ // It is wrong for this one, because this is not a runtime error. It says the
808
+ // module was built with a toolchain that has no server-rendered form, so every
809
+ // render of it will fail identically, forever, and no retry or fallback can
810
+ // change that. Degrading turns a build misconfiguration into silent data loss:
811
+ //
812
+ // renderToString(h('main', null, () => CompiledComponent()))
813
+ // -> "<main></main>" measured on origin/main
814
+ //
815
+ // The component simply vanished from the page. In development a console.warn
816
+ // fires; in production `_isDevMode` is false and nothing is logged at all, so
817
+ // the page ships with a hole in it and the server reports success.
818
+ //
819
+ // This mirrors the ownership rethrows already in the boundary branches: some
820
+ // throws are not the catcher's to absorb.
821
+ function _rethrowIfUnrenderable(e) {
822
+ if (e && e.code === 'ERR_COMPILED_JSX_IN_SSR') throw e;
823
+ }
824
+
825
+ function _isDomNode(value) {
826
+ return !!value && typeof value === 'object' && typeof (/** @type {any} */ (value).nodeType) === 'number';
827
+ }
828
+
829
+ function assertSafeTag(tag, vnode) {
830
+ if (typeof tag === 'string' && SAFE_TAG_NAME.test(tag)) return;
831
+ if (_isDomNode(vnode)) {
832
+ // ERROR_CODES.COMPILED_JSX_IN_SSR
758
833
  throw Object.assign(
759
- new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(tag)}`),
760
- { code: 'ERR_INVALID_SSR_TAG' },
834
+ new Error(
835
+ '[what-server] Cannot server-render a DOM node. A component compiled by ' +
836
+ 'what-compiler returns a cloned template (finished DOM), not a vnode, so it ' +
837
+ 'has no server-rendered form. Author server-rendered views with h(), or ' +
838
+ 'compile them with the automatic JSX runtime (jsxImportSource: ' +
839
+ '"what-framework") instead of what-compiler.'
840
+ ),
841
+ { code: 'ERR_COMPILED_JSX_IN_SSR' },
761
842
  );
762
843
  }
844
+ // ERROR_CODES.INVALID_SSR_TAG
845
+ throw Object.assign(
846
+ new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(tag)}`),
847
+ { code: 'ERR_INVALID_SSR_TAG' },
848
+ );
763
849
  }
764
850
 
765
851
  function renderAttrs(props) {
@@ -798,11 +884,12 @@ function renderAttrs(props) {
798
884
  // A resolved value that is itself a function is not an attribute value.
799
885
  if (typeof val === 'function') continue;
800
886
  }
801
- // aria-*/role are enumerated, so `false` is a real value and must survive:
802
- // an absent `aria-expanded` means "unsupported", `aria-expanded="false"`
803
- // means "collapsed". Every other attribute keeps HTML boolean semantics,
887
+ // aria-*/role and data-* are enumerated, so `false` is a real value and must
888
+ // survive: an absent `aria-expanded` means "unsupported",
889
+ // `aria-expanded="false"` means "collapsed", and `[data-open="false"]` is an
890
+ // ordinary selector. Every other attribute keeps HTML boolean semantics,
804
891
  // where false means omit. Checked before the falsy skip for that reason.
805
- if (val === false && _isAriaAttr(key)) {
892
+ if (val === false && (_isAriaAttr(key) || key.startsWith('data-'))) {
806
893
  out += ` ${key}="false"`;
807
894
  continue;
808
895
  }
@@ -828,8 +915,10 @@ function renderAttrs(props) {
828
915
  .join(';');
829
916
  out += ` style="${escapeHtml(css)}"`;
830
917
  } else if (val === true) {
831
- // ARIA attributes require explicit ="true", HTML boolean attrs can be bare
832
- if (key.startsWith('aria-') || key === 'role') {
918
+ // ARIA and data-* are enumerated and need an explicit ="true" so the
919
+ // markup matches what both client paths produce; genuine HTML boolean
920
+ // attributes can be bare.
921
+ if (key.startsWith('aria-') || key === 'role' || key.startsWith('data-')) {
833
922
  out += ` ${key}="true"`;
834
923
  } else {
835
924
  out += ` ${key}`;
package/src/islands.js CHANGED
@@ -524,6 +524,7 @@ function formEntries(form, submitter, multipart) {
524
524
  if (multipart) return data;
525
525
 
526
526
  const params = new URLSearchParams();
527
+ /** @type {string | null} */
527
528
  let droppedFile = null;
528
529
  for (const [key, value] of data) {
529
530
  if (typeof value === 'string') {
@@ -644,6 +645,7 @@ export function enhanceForms(selector = 'form[data-enhance]') {
644
645
  // on a server's say-so is not a default worth having. Listen for
645
646
  // form:response if you need that.
646
647
  if (proceed && response.ok && response.redirected) {
648
+ /** @type {string | null} */
647
649
  let target = null;
648
650
  try {
649
651
  const url = new URL(response.url, location.href);