what-server 0.13.4 → 0.13.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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 vt}from"what-core";var xt=new Map;function It(t){let e=t||vt();return e&&e.islandStores instanceof Map?e.islandStores:null}function ht(t){let e=typeof document<"u"?xt: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 x=new Map;function Bt(t,e){return x.has(t)||x.set(t,new Set),x.get(t).add(e),()=>{x.get(t)?.delete(e)}}function St(t){let e=x.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",At=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=At){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>At){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 Rt(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=>Rt(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 R=await d({method:"POST",headers:N(p.headers),body:m,query:Object.fromEntries(h.searchParams)});return new Response(R.body,{status:R.status,headers:R.headers})}let b=null,k=null;if(u&&(b=Rt(N(p.headers).cookie,q),!b)){b=K();let R=N(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;k=`${q}=${encodeURIComponent(b)}; Path=/; SameSite=Lax`+(R?"; 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 R=await s({headers:N(p.headers),body:m.json});return new Response(JSON.stringify(R.body),{status:R.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"},v={path:w,query:ne(h.search),config:B,route:O,params:U,request:p};if(n&&B.mode!=="server"){v.varyHeaders=N(p.headers);let m=await n.handle(v,()=>f(v));return new Response(m.html,{status:m.status||200,headers:C({"content-type":"text/html; charset=utf-8",...m.headers||{}})})}b&&(v.csrfToken=b);let J=await f(v),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(),A(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 A(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`<!--$-->${A(t())}<!--/$-->`;if(typeof t=="function"&&t._mapArray)try{return`<!--$-->${A(ot(t))}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(typeof t=="function")try{return`<!--$-->${A(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(A).join("")}<!--/[]-->`;if(st.has(t.tag))return"";if(Ct.has(t.tag))try{return(t.children||[]).map(A).join("")}catch(c){let u=c&&typeof c.then=="function";if(u&&t.tag==="__errorBoundary"||!u&&t.tag==="__suspense")throw c;return A(ct(t,u?null:c))}if(typeof t.tag=="function"){let c=le(),u=nt(t.tag),d;try{d=A(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(A).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="",r=e.resourceCounter;for(let a=0;a<Ot;a++){e.resourceCounter=r,n=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:n,head:at(e.head),loaderData:e.loaderData,resources:s,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,i=e.resourceCounter;for(let c=0;c<Ot&&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=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(Ae.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])=>`${Re(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"]),Ae=new Set(["srcdoc"]);function g(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function Re(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),r={};for(let[n,s]of e||[])r[n]=s._getSnapshot();return r}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 r=globalThis[L];if(r&&r.revalidatePath)return r.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 r=globalThis[L];if(r&&r.revalidateTag)return r.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 r=0;for(let n=0;n<t.length;n++)r|=t.charCodeAt(n)^e.charCodeAt(n);return r===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 r=e.id||zt(),{onError:n,onSuccess:s,revalidate:o}=e;typeof window>"u"&&q.set(r,{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":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 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 "${r}" timed out after ${c}ms`);throw l.code="TIMEOUT",n&&n(l),l}throw n&&n(f),f}finally{clearTimeout(d)}}return a._actionId=r,a._isAction=!0,a}function Rt(t,e={}){let{onSuccess:r,onError:n,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 r&&r(d,i),s&&i&&i.reset(),d}catch(d){throw n&&n(d,i),d}}}function Et(t){let e=_(!1),r=_(null),n=_(null);async function s(...o){e.set(!0),r.set(null);try{let a=await t(...o);return n.set(a),a}catch(a){throw r.set(a),a}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=Et(Rt(t,{resetOnSuccess:r}));function o(a){a.preventDefault();let i=new FormData(a.target);return n.current=a.target,s.trigger(i)}return{...s,handleSubmit:o,formRef:n}}function Xt(t,e){let r=_(t),n=_([]),s=_(t);function o(u){let d=e(r.peek(),u);Q(()=>{n.set([...n.peek(),u]),r.set(d)})}function a(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){o(u);try{let f=await d();return a(u,f),f}catch(f){throw i(u),f}}return{value:()=>r(),isPending:()=>n().length>0,addOptimistic:o,resolve:a,rollback:i,withOptimistic:c,set:u=>{r.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 r of e)try{r()}catch(n){console.error("[what] Revalidation error:",n)}}function M(t,e,r,n={}){let{csrfToken:s,skipCsrf:o=!1}=n;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(r)?a.fn(...r).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:r,onError:n,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),r&&r(c,...i),c}catch(c){throw o.error.set(c),n&&n(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:r,method:n="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||""})];r&&u.push(F("input",{type:"hidden",name:"_redirect",value:r}));let d={...a,method:n,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 re="/__what_action",j=1024*1024;function ne(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 U(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function rt(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 r=kt(t&&t._redirect);if(r)return r;let n=e.referer||e.referrer;if(n)try{let s=new URL(n,"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:r=!1}=t;return async function(s){if((s.method||"POST").toUpperCase()!=="POST")return U(405,{message:"Method Not Allowed"});let a=ne(s.headers),i=a["x-what-action"],c=a["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||{},y=h._action||h["data-action"]||s.query&&s.query.action;if(!y)return rt(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)),!r&&e&&!d)return rt(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:r});return k.status===200?{status:303,headers:{location:oe(h,a)},body:""}:rt(k.status,k.body&&k.body.message||"Action failed")}if(!i)return U(400,{message:"Missing X-What-Action header"});if(!r&&e&&!d)return U(403,{message:"Missing CSRF token"});let l=(s.body||{}).args,p=await M({headers:a},i,l,{csrfToken:d,skipCsrf:r});return U(p.status,p.body)}}function se(t={}){let e=t.basePath||re,r=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 r({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 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=j){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(),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,r)=>{let n=0,s=[];t.on("data",o=>{if(n+=o.length,n>j){let a=new Error("Body too large");a.code="BODY_TOO_LARGE",r(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",r)})}function ce(t={}){let e=H(t);return async function(r){let n={};try{let a=await V(r);if(a.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});n=B(a.raw,r.headers.get("content-type")||"")}catch{n={}}let s={};try{s=Object.fromEntries(new URL(r.url,"http://localhost").searchParams)}catch{}let o=await e({method:r.method,headers:r.headers,body:n,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",nt="what-csrf";function D(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((r,n)=>{e[n.toLowerCase()]=r}),e}function Ot(t,e){if(!t)return null;let r=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return r?decodeURIComponent(r[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(r){let{route:n,params:s,query:o,request:a,csrfToken:i}=r,c={default:n.component,loader:n.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:r.config&&r.config.tags||[],path:r.path}}}function A(t={}){let{routes:e=[],cache:r,render:n,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,nt)}:{skipCsrf:!0}),f=n||ye(o);return r&&(r.revalidatePath||r.revalidateTag)&&X({revalidatePath:r.revalidatePath,revalidateTag:r.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,nt),!b)){b=tt();let E=D(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;O=`${nt}=${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(r&&G.mode!=="server"){P.varyHeaders=D(p.headers);let g=await r.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(r,n,s){return n&&(r.__env=n),s&&(r.__ctx=s),e(r)}}}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 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 $&&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:r,children:n}=t;pt(e);let s=ht(r||{}),o=`<${e}${s}>`;if(yt.has(e))return o;let a=lt(r),i=a!=null?String(a):n.map(R).join("");return`${o}${i}</${e}>`}function Re(t,e){let r=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(r){let n=r[1],s=r[2],o=n.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:r,children:n}=t;pt(e);let s=ht(r||{}),o=`<${e}${s}>`;if(yt.has(e))return o;let a=lt(r),i=a!=null?String(a):n.map(m).join("");return`${o}${i}</${e}>`}function Sr(t){let e=T(void 0);return{body:S(e,()=>m(t)),head:ct(e.head)}}async function br(t,e={}){let r=t.default||t,n=typeof t.loader=="function"?await t.loader(e):void 0,s=T(n),o=e.params||{};return{body:S(s,()=>m(ot(r,{...o,loaderData:n}))),head:ct(s.head),loaderData:n}}var $t=12;async function Ee(t,e){e||(e=T(void 0));let r="",n=e.resourceCounter;for(let o=0;o<$t;o++){e.resourceCounter=n,r=S(e,()=>m(t));let a=[...e.resources.values()].filter(i=>i.status==="pending").map(i=>i.promise);if(a.length===0)break;await Promise.all(a)}let s={};for(let[o,a]of e.resources)a.status==="ready"&&(s[o]=a.value);return{body:r,head:ct(e.head),loaderData:e.loaderData,resources:s,ctx:e}}async function J(t,e={},r={}){let n=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(n,{...a,loaderData:s}),o),d={loaderData:s??null,resources:u,islandStores:St(o)};return Ae({body:i,head:c,payload:d,options:r})}function Ae({body:t,head:e,payload:r,options:n={}}){let s=n.lang||"en",o=`<script id="__what_data" type="application/json">${N(r)}<\/script>`,a=n.clientEntry?`<script type="module" src="${w(n.clientEntry)}"><\/script>`:"",c=(n.csrfToken?et(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}${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,i=e.resourceCounter;for(let c=0;c<$t&&a===null;c++){e.resourceCounter=i;let u=null;try{a=S(e,()=>(t.children||[]).map(m).join(""))}catch(d){if(d&&typeof d.then=="function")u=d;else throw d}if(a===null){let d=[...e.resources.values()].filter(f=>f.status==="pending").map(f=>f.promise);await Promise.all([u,...d].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:r,props:n,children:s}=t;pt(r);let o=ht(n||{});if(yield`<${r}${o}>`,!yt.has(r)){let a=lt(n);if(a!=null)yield String(a);else for(let i of s)yield*x(i,e);yield`</${r}>`}}function _r(t){return{mode:"static",...t}}function Rr(t,e={}){let r=T(e),n=S(r,()=>m(ot(t.component,e))),s=t.islands||[];return Te({title:t.title||"",meta:t.meta||{},body:n,islands:s,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function Te({title:t,meta:e,body:r,islands:n,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(`
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
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>
@@ -21,4 +21,4 @@ import{AsyncLocalStorage as Je}from"node:async_hooks";import{__installServerCont
21
21
  ${d}
22
22
  ${f}
23
23
  </body>
24
- </html>`}function Er(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[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 o=n;if(typeof o=="function"){try{o=o()}catch(a){$&&console.warn(`[what-server] Skipping attribute ${JSON.stringify(r)}: its value threw during SSR: ${a.message}`);continue}if(typeof o=="function")continue}if(o===!1&&ge(r)){e+=` ${r}="false"`;continue}if(!(o===!1||o==null)){if(!ke.test(r)){$&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(r)}`);continue}if(xe.has(s)){$&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(r)}`);continue}if(r==="className"||r==="class")e+=` class="${w(String(o))}"`;else if(r==="style"&&typeof o=="object"){let a=Object.entries(o).map(([i,c])=>`${$e(i)}:${c}`).join(";");e+=` style="${w(a)}"`}else if(o===!0)r.startsWith("aria-")||r==="role"?e+=` ${r}="true"`:e+=` ${r}`;else{if(Ce(r,o))continue;e+=` ${r}="${w(String(o))}"`}}}return e}function Ce(t,e){let r=t.toLowerCase();if(!ve.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 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 r=`http://${t.headers.host||"localhost"}${t.url}`,n=new Headers;for(let[o,a]of Object.entries(t.headers))a!=null&&n.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(r,{method:t.method,headers:n,body:s})}async function W(t,e){t.statusCode=e.status,e.headers.forEach((n,s)=>t.setHeader(s,n));let r=await e.text();t.end(r)}function It(t){return async function(r,n){try{let s=await Nt(r);if(s===mt)return await W(n,Pt());let o=await t(s);await W(n,o)}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 Ne(t={}){let e=A(t);return async function(n,s,o){let a=await Nt(n);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),r=Pe.createServer(It(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 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,(r,n)=>e[n]??"").replace(/\[(\w+)\]/g,(r,n)=>e[n]??"").replace(/[:*](\w+)/g,(r,n)=>e[n]??"")}function Fe(t,e){let r=Ht(t),n=Ht(gt(t,e==="/"?"":e));if(n!==r&&!n.startsWith(r+He))throw Object.assign(new Error(`[what-server] Refusing to write outside outDir: ${e}`),{code:"ERR_STATIC_WRITE_ESCAPE"});return n}async function Ue({routes:t=[],outDir:e,render:r,documentOptions:n={}}={}){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=r?await r(i,p):await J(i,p,n);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:r="nodejs22.x",files:n=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(n&&typeof n=="object"){l=u(t,"functions",`${e}.func`),await a(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,y]of Object.entries(n)){let b=u(l,h);await a(d(b),{recursive:!0}),await i(b,y)}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}}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,_r as definePage,Ue as exportStatic,ce as fetchActionHandler,Rt as formAction,tt as generateCsrfToken,Rr as generateStaticPage,Zt as getRegisteredActions,Bt as getRevalidationHandler,M as handleActionRequest,At as invalidatePath,se as nodeActionMiddleware,Kt as onRevalidate,J as renderDocument,br as renderPage,_e as renderToHydratableString,x as renderToStream,m as renderToString,Ee as renderToStringAsync,Sr as renderToStringWithHead,K as revalidatePath,Z as revalidateTag,N as serializeState,Er 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.4",
3
+ "version": "0.13.6",
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.4",
55
- "what-router": "^0.13.4"
54
+ "what-core": "^0.13.6",
55
+ "what-router": "^0.13.6"
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
 
@@ -499,10 +506,12 @@ export async function* renderToStream(vnode, ctx) {
499
506
 
500
507
  // Compiled keyed list: see _renderHydratable above.
501
508
  if (typeof vnode === 'function' && vnode._mapArray) {
509
+ /** @type {any} */
502
510
  let rows = null;
503
511
  try {
504
512
  rows = runWithServerContext(ctx, () => _mapArrayToArray(vnode));
505
513
  } catch (e) {
514
+ _rethrowIfUnrenderable(e);
506
515
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
507
516
  console.warn('[what-server] Error rendering keyed list in stream SSR:', e.message);
508
517
  }
@@ -517,6 +526,7 @@ export async function* renderToStream(vnode, ctx) {
517
526
  const value = runWithServerContext(ctx, () => vnode());
518
527
  yield* renderToStream(value, ctx);
519
528
  } catch (e) {
529
+ _rethrowIfUnrenderable(e);
520
530
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
521
531
  console.warn('[what-server] Error rendering reactive function in stream SSR:', e.message);
522
532
  }
@@ -542,6 +552,7 @@ export async function* renderToStream(vnode, ctx) {
542
552
  try {
543
553
  html = runWithServerContext(ctx, () => (vnode.children || []).map(renderToString).join(''));
544
554
  } catch (e) {
555
+ _rethrowIfUnrenderable(e);
545
556
  if (e && typeof e.then === 'function') throw e; // suspended; belongs to <Suspense>
546
557
  html = runWithServerContext(ctx, () => renderToString(_boundaryFallback(vnode, e)));
547
558
  }
@@ -594,6 +605,7 @@ export async function* renderToStream(vnode, ctx) {
594
605
  const resolved = result instanceof Promise ? await result : result;
595
606
  yield* renderToStream(resolved, ctx);
596
607
  } catch (e) {
608
+ _rethrowIfUnrenderable(e);
597
609
  if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
598
610
  console.warn('[what-server] Error rendering component in stream SSR:', e.message);
599
611
  }
@@ -607,7 +619,7 @@ export async function* renderToStream(vnode, ctx) {
607
619
  }
608
620
 
609
621
  const { tag, props, children } = vnode;
610
- assertSafeTag(tag);
622
+ assertSafeTag(tag, vnode);
611
623
  const attrs = renderAttrs(props || {});
612
624
  yield `<${tag}${attrs}>`;
613
625
 
@@ -766,14 +778,74 @@ const SAFE_ATTR_NAME = /^[a-zA-Z_:][a-zA-Z0-9:._-]*$/;
766
778
  // '__suspense' marker tag.
767
779
  const SAFE_TAG_NAME = /^[a-zA-Z_][a-zA-Z0-9._:-]*$/;
768
780
 
769
- function assertSafeTag(tag) {
770
- if (typeof tag !== 'string' || !SAFE_TAG_NAME.test(tag)) {
771
- // 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
772
833
  throw Object.assign(
773
- new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(tag)}`),
774
- { 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' },
775
842
  );
776
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
+ );
777
849
  }
778
850
 
779
851
  function renderAttrs(props) {
@@ -812,11 +884,12 @@ function renderAttrs(props) {
812
884
  // A resolved value that is itself a function is not an attribute value.
813
885
  if (typeof val === 'function') continue;
814
886
  }
815
- // aria-*/role are enumerated, so `false` is a real value and must survive:
816
- // an absent `aria-expanded` means "unsupported", `aria-expanded="false"`
817
- // 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,
818
891
  // where false means omit. Checked before the falsy skip for that reason.
819
- if (val === false && _isAriaAttr(key)) {
892
+ if (val === false && (_isAriaAttr(key) || key.startsWith('data-'))) {
820
893
  out += ` ${key}="false"`;
821
894
  continue;
822
895
  }
@@ -842,8 +915,10 @@ function renderAttrs(props) {
842
915
  .join(';');
843
916
  out += ` style="${escapeHtml(css)}"`;
844
917
  } else if (val === true) {
845
- // ARIA attributes require explicit ="true", HTML boolean attrs can be bare
846
- 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-')) {
847
922
  out += ` ${key}="true"`;
848
923
  } else {
849
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);