what-server 0.11.0 → 0.11.1

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.
@@ -1,2 +1 @@
1
1
  import{signal as p,batch as v}from"what-core";var h=null,k=!(typeof process<"u");async function S(e,t){if(h&&h.revalidatePath)return h.revalidatePath(e,t);k&&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 b(e,t){if(h&&h.revalidateTag)return h.revalidateTag(e,t);k&&console.warn(`[what] revalidateTag('${e}') had no effect: no cache engine is bound.`)}var A=new Map;function P(){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 I(){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 new Error("[what] No secure random source available for CSRF token generation")}function R(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 U(e){return`<meta name="what-csrf-token" content="${String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}">`}var T=0;function C(){return`a_${typeof crypto<"u"&&crypto.getRandomValues?Array.from(crypto.getRandomValues(new Uint8Array(6)),t=>t.toString(16).padStart(2,"0")).join(""):`c${(++T).toString(36)}_${Date.now().toString(36)}`}`}function O(e,t={}){let r=t.id||C(),{onError:n,onSuccess:l,revalidate:o}=t;typeof window>"u"&&A.set(r,{fn:e,options:t});async function a(...i){if(typeof window>"u")return e(...i);let s=t.timeout||3e4,u=new AbortController,c=setTimeout(()=>u.abort(),s);try{let f=P(),d={"Content-Type":"application/json","X-What-Action":r};f&&(d["X-CSRF-Token"]=f);let g=await fetch("/__what_action",{method:"POST",headers:d,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!g.ok){let w=await g.json().catch(()=>({message:"Action failed"}));throw new Error(w.message||"Action failed")}let y=await g.json();if(l&&l(y),o)for(let w of o)_(w);return y}catch(f){if(f.name==="AbortError"){let d=new Error(`Action "${r}" timed out after ${s}ms`);throw d.code="TIMEOUT",n&&n(d),d}throw n&&n(f),f}finally{clearTimeout(c)}}return a._actionId=r,a._isAction=!0,a}function x(e,t={}){let{onSuccess:r,onError:n,resetOnSuccess:l=!0}=t;return async o=>{let a,i;o instanceof Event?(o.preventDefault(),i=o.target,a=new FormData(i)):a=o;let s={},u=!1;for(let[c,f]of a.entries())typeof File<"u"&&f instanceof File&&(u=!0),s[c]?Array.isArray(s[c])?s[c].push(f):s[c]=[s[c],f]:s[c]=f;try{let c=u?await e(s,a):await e(s);return r&&r(c,i),l&&i&&i.reset(),c}catch(c){throw n&&n(c,i),c}}}function F(e){let t=p(!1),r=p(null),n=p(null);async function l(...o){t.set(!0),r.set(null);try{let a=await e(...o);return n.set(a),a}catch(a){throw r.set(a),a}finally{t.set(!1)}}return{trigger:l,isPending:()=>t(),error:()=>r(),data:()=>n(),reset:()=>{r.set(null),n.set(null)}}}function j(e,t={}){let{resetOnSuccess:r=!0}=t,n={current:null},l=F(x(e,{resetOnSuccess:r}));function o(a){a.preventDefault();let i=new FormData(a.target);return n.current=a.target,l.trigger(i)}return{...l,handleSubmit:o,formRef:n}}function M(e,t){let r=p(e),n=p([]),l=p(e);function o(u){let c=t(r.peek(),u);v(()=>{n.set([...n.peek(),u]),r.set(c)})}function a(u,c){v(()=>{if(n.set(n.peek().filter(f=>f!==u)),c!==void 0){l.set(c);let f=c;for(let d of n.peek())f=t(f,d);r.set(f)}})}function i(u,c){v(()=>{let f=n.peek().filter(y=>y!==u);n.set(f);let d=c!==void 0?c:l.peek();l.set(d);let g=d;for(let y of f)g=t(g,y);r.set(g)})}async function s(u,c){o(u);try{let f=await c();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:s,set:u=>{r.set(u),l.set(u)}}}var m=new Map;function N(e,t){return m.has(e)||m.set(e,new Set),m.get(e).add(t),()=>{m.get(e)?.delete(t)}}function _(e){let t=m.get(e);if(t)for(let r of t)try{r()}catch(n){console.error("[what] Revalidation error:",n)}}function H(e,t,r,n={}){let{csrfToken:l,skipCsrf:o=!1}=n;if(!o){if(!l)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(!R(i,l))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let a=A.get(t);return a?Array.isArray(r)?a.fn(...r).then(async i=>{let s=a.options||{};if(Array.isArray(s.revalidate))for(let u of s.revalidate)await S(u);if(Array.isArray(s.revalidateTags))for(let u of s.revalidateTags)await b(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 V(){return[...A.keys()]}function X(e,t={}){let{onSuccess:r,onError:n,onSettled:l}=t,o={isPending:p(!1),error:p(null),data:p(null)};async function a(...i){o.isPending.set(!0),o.error.set(null);try{let s=await e(...i);return o.data.set(s),r&&r(s,...i),s}catch(s){throw o.error.set(s),n&&n(s,...i),s}finally{o.isPending.set(!1),l&&l(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)}}}export{O as action,U as csrfMetaTag,x as formAction,I as generateCsrfToken,V as getRegisteredActions,H as handleActionRequest,_ as invalidatePath,N as onRevalidate,F as useAction,j as useFormAction,X as useMutation,M as useOptimistic,R as validateCsrfToken};
2
- //# sourceMappingURL=actions.min.js.map
package/dist/index.min.js CHANGED
@@ -1,4 +1,4 @@
1
- import{h as bt,runWithServerContext as H,beginHeadCollection as ie,endHeadCollection as q}from"what-core";var kt=new RegExp("[<>&\\u2028\\u2029]","g"),Rt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function x(t){return JSON.stringify(t).replace(kt,e=>Rt[e.charCodeAt(0)])}import{mount as Se,signal as Ae,batch as ke}from"what-core";var _t=new Map;function st(){let t={};for(let[e,n]of _t)t[e]=n._getSnapshot();return t}import{signal as S,batch as W}from"what-core";var k=null,it=!(typeof process<"u");function B(t){k=t}function Ct(){return k}async function V(t,e){if(k&&k.revalidatePath)return k.revalidatePath(t,e);it&&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 J(t,e){if(k&&k.revalidateTag)return k.revalidateTag(t,e);it&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var z=new Map;function Et(){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 X(){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 new Error("[what] No secure random source available for CSRF token generation")}function ct(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 Y(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}">`}var vt=0;function xt(){return`a_${typeof crypto<"u"&&crypto.getRandomValues?Array.from(crypto.getRandomValues(new Uint8Array(6)),e=>e.toString(16).padStart(2,"0")).join(""):`c${(++vt).toString(36)}_${Date.now().toString(36)}`}`}function Pt(t,e={}){let n=e.id||xt(),{onError:r,onSuccess:o,revalidate:a}=e;typeof window>"u"&&z.set(n,{fn:t,options:e});async function s(...i){if(typeof window>"u")return t(...i);let c=e.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let l=Et(),f={"Content-Type":"application/json","X-What-Action":n};l&&(f["X-CSRF-Token"]=l);let p=await fetch("/__what_action",{method:"POST",headers:f,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let m=await p.json().catch(()=>({message:"Action failed"}));throw new Error(m.message||"Action failed")}let h=await p.json();if(o&&o(h),a)for(let m of a)lt(m);return h}catch(l){if(l.name==="AbortError"){let f=new Error(`Action "${n}" timed out after ${c}ms`);throw f.code="TIMEOUT",r&&r(f),f}throw r&&r(l),l}finally{clearTimeout(d)}}return s._actionId=n,s._isAction=!0,s}function ut(t,e={}){let{onSuccess:n,onError:r,resetOnSuccess:o=!0}=e;return async a=>{let s,i;a instanceof Event?(a.preventDefault(),i=a.target,s=new FormData(i)):s=a;let c={},u=!1;for(let[d,l]of s.entries())typeof File<"u"&&l instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(l):c[d]=[c[d],l]:c[d]=l;try{let d=u?await t(c,s):await t(c);return n&&n(d,i),o&&i&&i.reset(),d}catch(d){throw r&&r(d,i),d}}}function dt(t){let e=S(!1),n=S(null),r=S(null);async function o(...a){e.set(!0),n.set(null);try{let s=await t(...a);return r.set(s),s}catch(s){throw n.set(s),s}finally{e.set(!1)}}return{trigger:o,isPending:()=>e(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Ot(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},o=dt(ut(t,{resetOnSuccess:n}));function a(s){s.preventDefault();let i=new FormData(s.target);return r.current=s.target,o.trigger(i)}return{...o,handleSubmit:a,formRef:r}}function $t(t,e){let n=S(t),r=S([]),o=S(t);function a(u){let d=e(n.peek(),u);W(()=>{r.set([...r.peek(),u]),n.set(d)})}function s(u,d){W(()=>{if(r.set(r.peek().filter(l=>l!==u)),d!==void 0){o.set(d);let l=d;for(let f of r.peek())l=e(l,f);n.set(l)}})}function i(u,d){W(()=>{let l=r.peek().filter(h=>h!==u);r.set(l);let f=d!==void 0?d:o.peek();o.set(f);let p=f;for(let h of l)p=e(p,h);n.set(p)})}async function c(u,d){a(u);try{let l=await d();return s(u,l),l}catch(l){throw i(u),l}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:a,resolve:s,rollback:i,withOptimistic:c,set:u=>{n.set(u),o.set(u)}}}var P=new Map;function Ht(t,e){return P.has(t)||P.set(t,new Set),P.get(t).add(e),()=>{P.get(t)?.delete(e)}}function lt(t){let e=P.get(t);if(e)for(let n of e)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function L(t,e,n,r={}){let{csrfToken:o,skipCsrf:a=!1}=r;if(!a){if(!o)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(!ct(i,o))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let s=z.get(e);return s?Array.isArray(n)?s.fn(...n).then(async i=>{let c=s.options||{};if(Array.isArray(c.revalidate))for(let u of c.revalidate)await V(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await J(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 It(){return[...z.keys()]}function jt(t,e={}){let{onSuccess:n,onError:r,onSettled:o}=e,a={isPending:S(!1),error:S(null),data:S(null)};async function s(...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),o&&o(a.data.peek(),a.error.peek(),...i)}}return{mutate:s,isPending:()=>a.isPending(),error:()=>a.error(),data:()=>a.data(),reset:()=>{a.error.set(null),a.data.set(null)}}}var Lt="/__what_action",pt=1024*1024;function Nt(t){if(!t)return{};if(typeof t.forEach=="function"&&typeof t.get=="function"){let n={};return t.forEach((r,o)=>{n[o.toLowerCase()]=r}),n}let e={};for(let n in t)e[n.toLowerCase()]=t[n];return e}function N(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function G(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 ft(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 Dt(t,e){let n=ft(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let o=new URL(r,"http://localhost"),a=ft(o.pathname+o.search);if(a)return a}catch{}return"/"}var Mt=new Set(["_action","data-action","_csrf","_redirect"]);function O(t={}){let{getCsrfToken:e,skipCsrf:n=!1}=t;return async function(o){if((o.method||"POST").toUpperCase()!=="POST")return N(405,{message:"Method Not Allowed"});let s=Nt(o.headers),i=s["x-what-action"],c=s["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=n?void 0:e?await e(o):void 0;if(u){let h=o.body||{},m=h._action||h["data-action"]||o.query&&o.query.action;if(!m)return G(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let w={...s};if(h._csrf&&!w["x-csrf-token"]&&(w["x-csrf-token"]=String(h._csrf)),!n&&e&&!d)return G(403,"Missing CSRF token");let _={};for(let[E,v]of Object.entries(h))Mt.has(E)||(_[E]=v);let T=await L({headers:w},m,[_],{csrfToken:d,skipCsrf:n});return T.status===200?{status:303,headers:{location:Dt(h,s)},body:""}:G(T.status,T.body&&T.body.message||"Action failed")}if(!i)return N(400,{message:"Missing X-What-Action header"});if(!n&&e&&!d)return N(403,{message:"Missing CSRF token"});let f=(o.body||{}).args,p=await L({headers:s},i,f,{csrfToken:d,skipCsrf:n});return N(p.status,p.body)}}function Ft(t={}){let e=t.basePath||Lt,n=O(t);return async function(o,a,s){let[i,c]=(o.url||"").split("?");if(i!==e||(o.method||"").toUpperCase()!=="POST")return s?s():void 0;let u;try{let f=await Ut(o);u=D(f,o.headers["content-type"]||"")}catch(f){a.writeHead(f.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),a.end(JSON.stringify({message:f.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let d=Object.fromEntries(new URLSearchParams(c||"")),l=await n({method:o.method,headers:o.headers,body:u,query:d});a.writeHead(l.status,l.headers),a.end(l.body)}}function D(t,e){if((e||"").includes("application/x-www-form-urlencoded")){let n={};for(let[r,o]of new URLSearchParams(String(t)))n[r]===void 0?n[r]=o:Array.isArray(n[r])?n[r].push(o):n[r]=[n[r],o];return n}return t==null||t===""?{}:JSON.parse(String(t))}async function Z(t,e=pt){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 o=r.getReader(),a=[],s=0;for(;;){let{done:i,value:c}=await o.read();if(i)break;if(c){if(s+=c.byteLength,s>e){try{await o.cancel()}catch{}return{tooLarge:!0}}a.push(c)}}return{raw:Buffer.concat(a.map(i=>Buffer.from(i))).toString("utf8")}}function Ut(t){return new Promise((e,n)=>{let r=0,o=[];t.on("data",a=>{if(r+=a.length,r>pt){let s=new Error("Body too large");s.code="BODY_TOO_LARGE",n(s),t.destroy?.();return}o.push(a)}),t.on("end",()=>{if(o.length===0)return e("");e(Buffer.concat(o).toString("utf8"))}),t.on("error",n)})}function Bt(t={}){let e=O(t);return async function(n){let r={};try{let s=await Z(n);if(s.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=D(s.raw,n.headers.get("content-type")||"")}catch{r={}}let o={};try{o=Object.fromEntries(new URL(n.url,"http://localhost").searchParams)}catch{}let a=await e({method:n.method,headers:n.headers,body:r,query:o});return new Response(a.body,{status:a.status,headers:a.headers})}}import{matchRoute as Vt,parseQuery as Jt}from"what-router/match";var Wt="/__what_action",zt="/__what_revalidate",K="what-csrf";function M(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((n,r)=>{e[r.toLowerCase()]=n}),e}function ht(t,e){if(!t)return null;let n=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function Xt(t){try{let e=await Z(t);return e.tooLarge?{tooLarge:!0}:D(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function Yt(t){try{return await t.json()}catch{return{}}}function Gt(t){return async function(n){let{route:r,params:o,query:a,request:s}=n,i={default:r.component,loader:r.loader},c=n.csrfToken?{...t,csrfToken:n.csrfToken}:t;return{html:await F(i,{params:o,query:a,request:s},c),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function R(t={}){let{routes:e=[],cache:n,render:r,revalidateWebhook:o,document:a={},notFound:s,basePath:i="",csrf:c=!0}=t,u=c!==!1&&!t.actionHandler,d=t.actionHandler||O(u?{getCsrfToken:f=>ht(f.headers&&f.headers.cookie,K)}:{skipCsrf:!0}),l=r||Gt(a);return n&&(n.revalidatePath||n.revalidateTag)&&B({revalidatePath:n.revalidatePath,revalidateTag:n.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===Wt){let y=await Xt(p);if(y&&y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await d({method:"POST",headers:M(p.headers),body:y,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let w=null,_=null;if(u&&(w=ht(M(p.headers).cookie,K),!w)){w=X();let A=M(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;_=`${K}=${encodeURIComponent(w)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let T=y=>(_&&(y["set-cookie"]=_),y);if(p.method==="POST"&&m===zt&&o){let y=await Yt(p),A=await o({headers:M(p.headers),body:y});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let E=Vt(m,e);if(!E){let y=s?s():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(y,{status:404,headers:T({"content-type":"text/html; charset=utf-8"})})}let{route:v,params:At}=E,U=v.page||{mode:v.mode||"client"},j={path:m,query:Jt(h.search),config:U,route:v,params:At,request:p};if(n&&U.mode!=="server"){let y=await n.handle(j,()=>l(j));return new Response(y.html,{status:y.status||200,headers:T({"content-type":"text/html; charset=utf-8",...y.headers||{}})})}w&&(j.csrfToken=w);let ot=await l(j),at=T({"content-type":"text/html; charset=utf-8"});return U.mode==="server"&&(at["Cache-Control"]="private, no-store"),new Response(ot.html,{status:ot.status||200,headers:at})}}import Zt from"node:http";async function mt(t){let n=`http://${t.headers.host||"localhost"}${t.url}`,r=new Headers;for(let[a,s]of Object.entries(t.headers))s!=null&&r.set(a,Array.isArray(s)?s.join(", "):String(s));let o;if(t.method!=="GET"&&t.method!=="HEAD"){let a=[];for await(let s of t)a.push(s);a.length&&(o=Buffer.concat(a))}return new Request(n,{method:t.method,headers:r,body:o})}async function yt(t,e){t.statusCode=e.status,e.headers.forEach((r,o)=>t.setHeader(o,r));let n=await e.text();t.end(n)}function gt(t){return async function(n,r){try{let o=await mt(n),a=await t(o);await yt(r,a)}catch(o){r.headersSent||r.writeHead(500,{"content-type":"text/html; charset=utf-8"}),r.end("<!DOCTYPE html><html><body><h1>500 \u2014 Server Error</h1></body></html>"),console.error("[what-server] request error:",o)}}}function Kt(t={}){let e=R(t);return async function(r,o,a){let s=await mt(r),i=await e(s);if(i.status===404&&typeof a=="function")return a();await yt(o,i)}}function Qt(t={}){let e=R(t),n=Zt.createServer(gt(e)),{scheduler:r}=t;if(r){r.start();let o=()=>{try{r.stop()}catch{}n.close()};process.once("SIGTERM",o),process.once("SIGINT",o)}return n}import{mkdir as qt,writeFile as wt}from"node:fs/promises";import{join as Q}from"node:path";import{matchRoute as te}from"what-router/match";function ee(t){return t.includes(":")||t.includes("*")||t.includes("[")}function ne(t,e){return t.replace(/\[\.\.\.(\w+)\]/g,(n,r)=>e[r]??"").replace(/\[(\w+)\]/g,(n,r)=>e[r]??"").replace(/[:*](\w+)/g,(n,r)=>e[r]??"")}async function re({routes:t=[],outDir:e,render:n,documentOptions:r={}}={}){let o=[];for(let a of t){let s=a.page&&a.page.mode||a.mode;if(s!=="static"&&s!=="hybrid")continue;let i={default:a.component,loader:a.loader},c=[a.path];if(ee(a.path)){if(typeof a.getStaticPaths!="function")continue;c=((await a.getStaticPaths()).paths||[]).map(d=>ne(a.path,d.params||{}))}for(let u of c){let d=te(u,[a]),f={params:d?d.params:{},query:{}},p=n?await n(i,f):await F(i,f,r),h=Q(e,u==="/"?"":u);if(await qt(h,{recursive:!0}),await wt(Q(h,"index.html"),p),typeof a.loader=="function"){let m=await a.loader(f);await wt(Q(h,"__what_data.json"),x({loaderData:m}))}o.push(u)}}return{pages:o}}function oe(t={}){let e=R(t);return{async fetch(n,r,o){return r&&(n.__env=r),o&&(n.__ctx=o),e(n)}}}function ae(t={}){return R(t)}async function se({outDir:t=".vercel/output",functionName:e="render",runtime:n="nodejs22.x",files:r=null,handler:o="index.mjs",staticDir:a=null}={}){let{mkdir:s,writeFile:i,cp:c}=await import("node:fs/promises"),{join:u,dirname:d}=await import("node:path");await s(t,{recursive:!0});let l={version:3,routes:[{handle:"filesystem"},{src:"/.*",dest:`/${e}`}]};await i(u(t,"config.json"),JSON.stringify(l,null,2)),a&&await c(a,u(t,"static"),{recursive:!0});let f=null;if(r&&typeof r=="object"){f=u(t,"functions",`${e}.func`),await s(f,{recursive:!0});let p={runtime:n,handler:o,launcherType:"Nodejs",shouldAddHelpers:!1,supportsResponseStreaming:!0};await i(u(f,".vc-config.json"),JSON.stringify(p,null,2));for(let[h,m]of Object.entries(r)){let w=u(f,h);await s(d(w),{recursive:!0}),await i(w,m)}o in r||console.warn(`[what-server] buildVercelOutput: files does not include the handler entry "${o}" \u2014 the deploy will 500 until your build emits it.`)}return{config:l,outDir:t,functionDir:f}}function I(t){return{head:ie(),loaderData:t,resources:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var St=0;function ce(){St=0}function ue(){return"h"+St++}function qe(t){return ce(),C(t)}function C(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`<!--$-->${C(t())}<!--/$-->`;if(typeof t=="function")try{return`<!--$-->${C(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(C).join("")}<!--/[]-->`;if(typeof t.tag=="function"){let c=ue(),u=t.tag({...t.props,children:t.children}),d=C(u);return de(d,c)}let{tag:e,props:n,children:r}=t,o=nt(n||{}),a=`<${e}${o}>`;if(rt.has(e))return a;let s=et(n),i=s!=null?String(s):r.map(C).join("");return`${a}${i}</${e}>`}function de(t,e){let n=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],o=n[2],a=r.length+1+o.length;return t.slice(0,a)+` data-hk="${e}"`+t.slice(a)}return t}function b(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 b(t());if(typeof t=="function")try{return b(t())}catch{return typeof process<"u",""}if(Array.isArray(t))return t.map(b).join("");if(t.tag==="__suspense")try{return(t.children||[]).map(b).join("")}catch(c){if(c&&typeof c.then=="function")return b(t.props&&t.props.fallback);throw c}if(typeof t.tag=="function"){let c=t.tag({...t.props,children:t.children});return b(c)}let{tag:e,props:n,children:r}=t,o=nt(n||{}),a=`<${e}${o}>`;if(rt.has(e))return a;let s=et(n),i=s!=null?String(s):r.map(b).join("");return`${a}${i}</${e}>`}function tn(t){let e=I(void 0);return{body:H(e,()=>b(t)),head:q(e.head)}}async function en(t,e={}){let n=t.default||t,r=typeof t.loader=="function"?await t.loader(e):void 0,o=I(r),a=e.params||{};return{body:H(o,()=>b(bt(n,{...a,loaderData:r}))),head:q(o.head),loaderData:r}}var Tt=12;async function le(t,e){e||(e=I(void 0));let n="";for(let o=0;o<Tt;o++){n=H(e,()=>b(t));let a=[...e.resources.values()].filter(s=>s.status==="pending").map(s=>s.promise);if(a.length===0)break;await Promise.all(a)}let r={};for(let[o,a]of e.resources)a.status==="ready"&&(r[o]=a.value);return{body:n,head:q(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function F(t,e={},n={}){let r=t.default||t,o=typeof t.loader=="function"?await t.loader(e):void 0,a=I(o),s=e.params||{},{body:i,head:c,resources:u}=await le(bt(r,{...s,loaderData:o}),a),d={loaderData:o??null,resources:u,islandStores:st()};return fe({body:i,head:c,payload:d,options:n})}function fe({body:t,head:e,payload:n,options:r={}}){let o=r.lang||"en",a=`<script id="__what_data" type="application/json">${x(n)}<\/script>`,s=r.clientEntry?`<script type="module" src="${g(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?Y(r.csrfToken):"")+(r.head||""),u=r.bodyClass?` class="${g(r.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${g(o)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${e||""}${c}</head><body${u}>${t}${a}${s}</body></html>`}async function*$(t,e){if(e===void 0&&(e=I(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){yield*$(t(),e);return}if(typeof t=="function"){try{yield*$(t(),e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let s of t)yield*$(s,e);return}if(t.tag==="__suspense"){let s=null;for(let i=0;i<Tt&&s===null;i++){let c=null;try{s=H(e,()=>(t.children||[]).map(b).join(""))}catch(u){if(u&&typeof u.then=="function")c=u;else throw u}if(s===null){let u=[...e.resources.values()].filter(d=>d.status==="pending").map(d=>d.promise);await Promise.all([c,...u].filter(Boolean))}}s===null&&(s=H(e,()=>b(t.props&&t.props.fallback))),yield s;return}if(typeof t.tag=="function"){try{let s=t.tag({...t.props,children:t.children}),i=s instanceof Promise?await s:s;yield*$(i,e)}catch(s){typeof process<"u",yield tt?`<!-- SSR Error: ${g(s.message||"Component error")} -->`:"<!-- SSR Error -->"}return}let{tag:n,props:r,children:o}=t,a=nt(r||{});if(yield`<${n}${a}>`,!rt.has(n)){let s=et(r);if(s!=null)yield String(s);else for(let i of o)yield*$(i,e);yield`</${n}>`}}function nn(t){return{mode:"static",...t}}function rn(t,e={}){let n=t.component(e),r=b(n),o=t.islands||[];return pe({title:t.title||"",meta:t.meta||{},body:r,islands:o,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function pe({title:t,meta:e,body:n,islands:r,scripts:o,styles:a,mode:s}){let i=Object.entries(e).map(([f,p])=>`<meta name="${g(f)}" content="${g(p)}">`).join(`
1
+ import{h as St,runWithServerContext as H,beginHeadCollection as ie,endHeadCollection as tt}from"what-core";var kt=new RegExp("[<>&\\u2028\\u2029]","g"),Rt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function x(t){return JSON.stringify(t).replace(kt,e=>Rt[e.charCodeAt(0)])}import{mount as Se,signal as Ae,batch as ke}from"what-core";var _t=new Map;function it(){let t={};for(let[e,n]of _t)t[e]=n._getSnapshot();return t}import{signal as S,batch as z}from"what-core";var A=null,ct=!(typeof process<"u");function V(t){A=t}function Ct(){return A}async function J(t,e){if(A&&A.revalidatePath)return A.revalidatePath(t,e);ct&&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 W(t,e){if(A&&A.revalidateTag)return A.revalidateTag(t,e);ct&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var X=new Map;function Et(){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 Y(){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 new Error("[what] No secure random source available for CSRF token generation")}function ut(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 G(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}">`}var vt=0;function xt(){return`a_${typeof crypto<"u"&&crypto.getRandomValues?Array.from(crypto.getRandomValues(new Uint8Array(6)),e=>e.toString(16).padStart(2,"0")).join(""):`c${(++vt).toString(36)}_${Date.now().toString(36)}`}`}function Pt(t,e={}){let n=e.id||xt(),{onError:r,onSuccess:o,revalidate:a}=e;typeof window>"u"&&X.set(n,{fn:t,options:e});async function s(...i){if(typeof window>"u")return t(...i);let c=e.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let l=Et(),f={"Content-Type":"application/json","X-What-Action":n};l&&(f["X-CSRF-Token"]=l);let p=await fetch("/__what_action",{method:"POST",headers:f,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let m=await p.json().catch(()=>({message:"Action failed"}));throw new Error(m.message||"Action failed")}let h=await p.json();if(o&&o(h),a)for(let m of a)ft(m);return h}catch(l){if(l.name==="AbortError"){let f=new Error(`Action "${n}" timed out after ${c}ms`);throw f.code="TIMEOUT",r&&r(f),f}throw r&&r(l),l}finally{clearTimeout(d)}}return s._actionId=n,s._isAction=!0,s}function dt(t,e={}){let{onSuccess:n,onError:r,resetOnSuccess:o=!0}=e;return async a=>{let s,i;a instanceof Event?(a.preventDefault(),i=a.target,s=new FormData(i)):s=a;let c={},u=!1;for(let[d,l]of s.entries())typeof File<"u"&&l instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(l):c[d]=[c[d],l]:c[d]=l;try{let d=u?await t(c,s):await t(c);return n&&n(d,i),o&&i&&i.reset(),d}catch(d){throw r&&r(d,i),d}}}function lt(t){let e=S(!1),n=S(null),r=S(null);async function o(...a){e.set(!0),n.set(null);try{let s=await t(...a);return r.set(s),s}catch(s){throw n.set(s),s}finally{e.set(!1)}}return{trigger:o,isPending:()=>e(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Ot(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},o=lt(dt(t,{resetOnSuccess:n}));function a(s){s.preventDefault();let i=new FormData(s.target);return r.current=s.target,o.trigger(i)}return{...o,handleSubmit:a,formRef:r}}function $t(t,e){let n=S(t),r=S([]),o=S(t);function a(u){let d=e(n.peek(),u);z(()=>{r.set([...r.peek(),u]),n.set(d)})}function s(u,d){z(()=>{if(r.set(r.peek().filter(l=>l!==u)),d!==void 0){o.set(d);let l=d;for(let f of r.peek())l=e(l,f);n.set(l)}})}function i(u,d){z(()=>{let l=r.peek().filter(h=>h!==u);r.set(l);let f=d!==void 0?d:o.peek();o.set(f);let p=f;for(let h of l)p=e(p,h);n.set(p)})}async function c(u,d){a(u);try{let l=await d();return s(u,l),l}catch(l){throw i(u),l}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:a,resolve:s,rollback:i,withOptimistic:c,set:u=>{n.set(u),o.set(u)}}}var P=new Map;function Ht(t,e){return P.has(t)||P.set(t,new Set),P.get(t).add(e),()=>{P.get(t)?.delete(e)}}function ft(t){let e=P.get(t);if(e)for(let n of e)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function L(t,e,n,r={}){let{csrfToken:o,skipCsrf:a=!1}=r;if(!a){if(!o)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(!ut(i,o))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let s=X.get(e);return s?Array.isArray(n)?s.fn(...n).then(async i=>{let c=s.options||{};if(Array.isArray(c.revalidate))for(let u of c.revalidate)await J(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await W(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 It(){return[...X.keys()]}function jt(t,e={}){let{onSuccess:n,onError:r,onSettled:o}=e,a={isPending:S(!1),error:S(null),data:S(null)};async function s(...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),o&&o(a.data.peek(),a.error.peek(),...i)}}return{mutate:s,isPending:()=>a.isPending(),error:()=>a.error(),data:()=>a.data(),reset:()=>{a.error.set(null),a.data.set(null)}}}var Lt="/__what_action",ht=1024*1024;function Nt(t){if(!t)return{};if(typeof t.forEach=="function"&&typeof t.get=="function"){let n={};return t.forEach((r,o)=>{n[o.toLowerCase()]=r}),n}let e={};for(let n in t)e[n.toLowerCase()]=t[n];return e}function N(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function Z(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 pt(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 Dt(t,e){let n=pt(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let o=new URL(r,"http://localhost"),a=pt(o.pathname+o.search);if(a)return a}catch{}return"/"}var Mt=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function O(t={}){let{getCsrfToken:e,skipCsrf:n=!1}=t;return async function(o){if((o.method||"POST").toUpperCase()!=="POST")return N(405,{message:"Method Not Allowed"});let s=Nt(o.headers),i=s["x-what-action"],c=s["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=n?void 0:e?await e(o):void 0;if(u){let h=o.body||{},m=h._action||h["data-action"]||o.query&&o.query.action;if(!m)return Z(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let w={...s},_=h._csrf??h["what-csrf-token"];if(_&&!w["x-csrf-token"]&&(w["x-csrf-token"]=String(_)),!n&&e&&!d)return Z(403,"Missing CSRF token");let C={};for(let[E,U]of Object.entries(h))Mt.has(E)||(C[E]=U);let R=await L({headers:w},m,[C],{csrfToken:d,skipCsrf:n});return R.status===200?{status:303,headers:{location:Dt(h,s)},body:""}:Z(R.status,R.body&&R.body.message||"Action failed")}if(!i)return N(400,{message:"Missing X-What-Action header"});if(!n&&e&&!d)return N(403,{message:"Missing CSRF token"});let f=(o.body||{}).args,p=await L({headers:s},i,f,{csrfToken:d,skipCsrf:n});return N(p.status,p.body)}}function Ft(t={}){let e=t.basePath||Lt,n=O(t);return async function(o,a,s){let[i,c]=(o.url||"").split("?");if(i!==e||(o.method||"").toUpperCase()!=="POST")return s?s():void 0;let u;try{let f=await Ut(o);u=D(f,o.headers["content-type"]||"")}catch(f){a.writeHead(f.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),a.end(JSON.stringify({message:f.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let d=Object.fromEntries(new URLSearchParams(c||"")),l=await n({method:o.method,headers:o.headers,body:u,query:d});a.writeHead(l.status,l.headers),a.end(l.body)}}function D(t,e){if((e||"").includes("application/x-www-form-urlencoded")){let n={};for(let[r,o]of new URLSearchParams(String(t)))n[r]===void 0?n[r]=o:Array.isArray(n[r])?n[r].push(o):n[r]=[n[r],o];return n}return t==null||t===""?{}:JSON.parse(String(t))}async function K(t,e=ht){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 o=r.getReader(),a=[],s=0;for(;;){let{done:i,value:c}=await o.read();if(i)break;if(c){if(s+=c.byteLength,s>e){try{await o.cancel()}catch{}return{tooLarge:!0}}a.push(c)}}return{raw:Buffer.concat(a.map(i=>Buffer.from(i))).toString("utf8")}}function Ut(t){return new Promise((e,n)=>{let r=0,o=[];t.on("data",a=>{if(r+=a.length,r>ht){let s=new Error("Body too large");s.code="BODY_TOO_LARGE",n(s),t.destroy?.();return}o.push(a)}),t.on("end",()=>{if(o.length===0)return e("");e(Buffer.concat(o).toString("utf8"))}),t.on("error",n)})}function Bt(t={}){let e=O(t);return async function(n){let r={};try{let s=await K(n);if(s.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=D(s.raw,n.headers.get("content-type")||"")}catch{r={}}let o={};try{o=Object.fromEntries(new URL(n.url,"http://localhost").searchParams)}catch{}let a=await e({method:n.method,headers:n.headers,body:r,query:o});return new Response(a.body,{status:a.status,headers:a.headers})}}import{matchRoute as Vt,parseQuery as Jt}from"what-router/match";var Wt="/__what_action",zt="/__what_revalidate",Q="what-csrf";function M(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((n,r)=>{e[r.toLowerCase()]=n}),e}function mt(t,e){if(!t)return null;let n=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function Xt(t){try{let e=await K(t);return e.tooLarge?{tooLarge:!0}:D(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function Yt(t){try{return await t.json()}catch{return{}}}function Gt(t){return async function(n){let{route:r,params:o,query:a,request:s}=n,i={default:r.component,loader:r.loader},c=n.csrfToken?{...t,csrfToken:n.csrfToken}:t;return{html:await F(i,{params:o,query:a,request:s},c),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function k(t={}){let{routes:e=[],cache:n,render:r,revalidateWebhook:o,document:a={},notFound:s,basePath:i="",csrf:c=!0}=t,u=c!==!1&&!t.actionHandler,d=t.actionHandler||O(u?{getCsrfToken:f=>mt(f.headers&&f.headers.cookie,Q)}:{skipCsrf:!0}),l=r||Gt(a);return n&&(n.revalidatePath||n.revalidateTag)&&V({revalidatePath:n.revalidatePath,revalidateTag:n.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===Wt){let y=await Xt(p);if(y&&y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let T=await d({method:"POST",headers:M(p.headers),body:y,query:Object.fromEntries(h.searchParams)});return new Response(T.body,{status:T.status,headers:T.headers})}let w=null,_=null;if(u&&(w=mt(M(p.headers).cookie,Q),!w)){w=Y();let T=M(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;_=`${Q}=${encodeURIComponent(w)}; Path=/; SameSite=Lax`+(T?"; Secure":"")}let C=y=>(_&&(y["set-cookie"]=_),y);if(p.method==="POST"&&m===zt&&o){let y=await Yt(p),T=await o({headers:M(p.headers),body:y});return new Response(JSON.stringify(T.body),{status:T.status,headers:{"content-type":"application/json"}})}let R=Vt(m,e);if(!R){let y=s?s():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(y,{status:404,headers:C({"content-type":"text/html; charset=utf-8"})})}let{route:E,params:U}=R,B=E.page||{mode:E.mode||"client"},j={path:m,query:Jt(h.search),config:B,route:E,params:U,request:p};if(n&&B.mode!=="server"){let y=await n.handle(j,()=>l(j));return new Response(y.html,{status:y.status||200,headers:C({"content-type":"text/html; charset=utf-8",...y.headers||{}})})}w&&(j.csrfToken=w);let at=await l(j),st=C({"content-type":"text/html; charset=utf-8"});return B.mode==="server"&&(st["Cache-Control"]="private, no-store"),new Response(at.html,{status:at.status||200,headers:st})}}import Zt from"node:http";async function yt(t){let n=`http://${t.headers.host||"localhost"}${t.url}`,r=new Headers;for(let[a,s]of Object.entries(t.headers))s!=null&&r.set(a,Array.isArray(s)?s.join(", "):String(s));let o;if(t.method!=="GET"&&t.method!=="HEAD"){let a=[];for await(let s of t)a.push(s);a.length&&(o=Buffer.concat(a))}return new Request(n,{method:t.method,headers:r,body:o})}async function gt(t,e){t.statusCode=e.status,e.headers.forEach((r,o)=>t.setHeader(o,r));let n=await e.text();t.end(n)}function wt(t){return async function(n,r){try{let o=await yt(n),a=await t(o);await gt(r,a)}catch(o){r.headersSent||r.writeHead(500,{"content-type":"text/html; charset=utf-8"}),r.end("<!DOCTYPE html><html><body><h1>500 \u2014 Server Error</h1></body></html>"),console.error("[what-server] request error:",o)}}}function Kt(t={}){let e=k(t);return async function(r,o,a){let s=await yt(r),i=await e(s);if(i.status===404&&typeof a=="function")return a();await gt(o,i)}}function Qt(t={}){let e=k(t),n=Zt.createServer(wt(e)),{scheduler:r}=t;if(r){r.start();let o=()=>{try{r.stop()}catch{}n.close()};process.once("SIGTERM",o),process.once("SIGINT",o)}return n}import{mkdir as qt,writeFile as bt}from"node:fs/promises";import{join as q}from"node:path";import{matchRoute as te}from"what-router/match";function ee(t){return t.includes(":")||t.includes("*")||t.includes("[")}function ne(t,e){return t.replace(/\[\.\.\.(\w+)\]/g,(n,r)=>e[r]??"").replace(/\[(\w+)\]/g,(n,r)=>e[r]??"").replace(/[:*](\w+)/g,(n,r)=>e[r]??"")}async function re({routes:t=[],outDir:e,render:n,documentOptions:r={}}={}){let o=[];for(let a of t){let s=a.page&&a.page.mode||a.mode;if(s!=="static"&&s!=="hybrid")continue;let i={default:a.component,loader:a.loader},c=[a.path];if(ee(a.path)){if(typeof a.getStaticPaths!="function")continue;c=((await a.getStaticPaths()).paths||[]).map(d=>ne(a.path,d.params||{}))}for(let u of c){let d=te(u,[a]),f={params:d?d.params:{},query:{}},p=n?await n(i,f):await F(i,f,r),h=q(e,u==="/"?"":u);if(await qt(h,{recursive:!0}),await bt(q(h,"index.html"),p),typeof a.loader=="function"){let m=await a.loader(f);await bt(q(h,"__what_data.json"),x({loaderData:m}))}o.push(u)}}return{pages:o}}function oe(t={}){let e=k(t);return{async fetch(n,r,o){return r&&(n.__env=r),o&&(n.__ctx=o),e(n)}}}function ae(t={}){return k(t)}async function se({outDir:t=".vercel/output",functionName:e="render",runtime:n="nodejs22.x",files:r=null,handler:o="index.mjs",staticDir:a=null}={}){let{mkdir:s,writeFile:i,cp:c}=await import("node:fs/promises"),{join:u,dirname:d}=await import("node:path");await s(t,{recursive:!0});let l={version:3,routes:[{handle:"filesystem"},{src:"/.*",dest:`/${e}`}]};await i(u(t,"config.json"),JSON.stringify(l,null,2)),a&&await c(a,u(t,"static"),{recursive:!0});let f=null;if(r&&typeof r=="object"){f=u(t,"functions",`${e}.func`),await s(f,{recursive:!0});let p={runtime:n,handler:o,launcherType:"Nodejs",shouldAddHelpers:!1,supportsResponseStreaming:!0};await i(u(f,".vc-config.json"),JSON.stringify(p,null,2));for(let[h,m]of Object.entries(r)){let w=u(f,h);await s(d(w),{recursive:!0}),await i(w,m)}o in r||console.warn(`[what-server] buildVercelOutput: files does not include the handler entry "${o}" \u2014 the deploy will 500 until your build emits it.`)}return{config:l,outDir:t,functionDir:f}}function I(t){return{head:ie(),loaderData:t,resources:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var Tt=0;function ce(){Tt=0}function ue(){return"h"+Tt++}function qe(t){return ce(),v(t)}function v(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`<!--$-->${v(t())}<!--/$-->`;if(typeof t=="function")try{return`<!--$-->${v(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(v).join("")}<!--/[]-->`;if(typeof t.tag=="function"){let c=ue(),u=t.tag({...t.props,children:t.children}),d=v(u);return de(d,c)}let{tag:e,props:n,children:r}=t,o=rt(n||{}),a=`<${e}${o}>`;if(ot.has(e))return a;let s=nt(n),i=s!=null?String(s):r.map(v).join("");return`${a}${i}</${e}>`}function de(t,e){let n=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],o=n[2],a=r.length+1+o.length;return t.slice(0,a)+` data-hk="${e}"`+t.slice(a)}return t}function b(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 b(t());if(typeof t=="function")try{return b(t())}catch{return typeof process<"u",""}if(Array.isArray(t))return t.map(b).join("");if(t.tag==="__suspense")try{return(t.children||[]).map(b).join("")}catch(c){if(c&&typeof c.then=="function")return b(t.props&&t.props.fallback);throw c}if(typeof t.tag=="function"){let c=t.tag({...t.props,children:t.children});return b(c)}let{tag:e,props:n,children:r}=t,o=rt(n||{}),a=`<${e}${o}>`;if(ot.has(e))return a;let s=nt(n),i=s!=null?String(s):r.map(b).join("");return`${a}${i}</${e}>`}function tn(t){let e=I(void 0);return{body:H(e,()=>b(t)),head:tt(e.head)}}async function en(t,e={}){let n=t.default||t,r=typeof t.loader=="function"?await t.loader(e):void 0,o=I(r),a=e.params||{};return{body:H(o,()=>b(St(n,{...a,loaderData:r}))),head:tt(o.head),loaderData:r}}var At=12;async function le(t,e){e||(e=I(void 0));let n="";for(let o=0;o<At;o++){n=H(e,()=>b(t));let a=[...e.resources.values()].filter(s=>s.status==="pending").map(s=>s.promise);if(a.length===0)break;await Promise.all(a)}let r={};for(let[o,a]of e.resources)a.status==="ready"&&(r[o]=a.value);return{body:n,head:tt(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function F(t,e={},n={}){let r=t.default||t,o=typeof t.loader=="function"?await t.loader(e):void 0,a=I(o),s=e.params||{},{body:i,head:c,resources:u}=await le(St(r,{...s,loaderData:o}),a),d={loaderData:o??null,resources:u,islandStores:it()};return fe({body:i,head:c,payload:d,options:n})}function fe({body:t,head:e,payload:n,options:r={}}){let o=r.lang||"en",a=`<script id="__what_data" type="application/json">${x(n)}<\/script>`,s=r.clientEntry?`<script type="module" src="${g(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?G(r.csrfToken):"")+(r.head||""),u=r.bodyClass?` class="${g(r.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${g(o)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${e||""}${c}</head><body${u}>${t}${a}${s}</body></html>`}async function*$(t,e){if(e===void 0&&(e=I(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){yield*$(t(),e);return}if(typeof t=="function"){try{yield*$(t(),e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let s of t)yield*$(s,e);return}if(t.tag==="__suspense"){let s=null;for(let i=0;i<At&&s===null;i++){let c=null;try{s=H(e,()=>(t.children||[]).map(b).join(""))}catch(u){if(u&&typeof u.then=="function")c=u;else throw u}if(s===null){let u=[...e.resources.values()].filter(d=>d.status==="pending").map(d=>d.promise);await Promise.all([c,...u].filter(Boolean))}}s===null&&(s=H(e,()=>b(t.props&&t.props.fallback))),yield s;return}if(typeof t.tag=="function"){try{let s=t.tag({...t.props,children:t.children}),i=s instanceof Promise?await s:s;yield*$(i,e)}catch(s){typeof process<"u",yield et?`<!-- SSR Error: ${g(s.message||"Component error")} -->`:"<!-- SSR Error -->"}return}let{tag:n,props:r,children:o}=t,a=rt(r||{});if(yield`<${n}${a}>`,!ot.has(n)){let s=nt(r);if(s!=null)yield String(s);else for(let i of o)yield*$(i,e);yield`</${n}>`}}function nn(t){return{mode:"static",...t}}function rn(t,e={}){let n=t.component(e),r=b(n),o=t.islands||[];return pe({title:t.title||"",meta:t.meta||{},body:r,islands:o,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function pe({title:t,meta:e,body:n,islands:r,scripts:o,styles:a,mode:s}){let i=Object.entries(e).map(([f,p])=>`<meta name="${g(f)}" content="${g(p)}">`).join(`
2
2
  `),c=a.map(f=>`<link rel="stylesheet" href="${g(f)}">`).join(`
3
3
  `),u=r.length>0?`
4
4
  <script type="module">
@@ -21,5 +21,4 @@ import{h as bt,runWithServerContext as H,beginHeadCollection as ie,endHeadCollec
21
21
  ${d}
22
22
  ${l}
23
23
  </body>
24
- </html>`}function on(t){return t._server=!0,t}var tt=!(typeof process<"u");function et(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"&&tt&&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 he=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/;function nt(t){let e="";for(let[n,r]of Object.entries(t))if(!(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")&&!(n.startsWith("on")&&n.length>2)&&!(r===!1||r==null)){if(!he.test(n)){tt&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")e+=` class="${g(String(r))}"`;else if(n==="style"&&typeof r=="object"){let o=Object.entries(r).map(([a,s])=>`${ge(a)}:${s}`).join(";");e+=` style="${g(o)}"`}else if(r===!0)n.startsWith("aria-")||n==="role"?e+=` ${n}="true"`:e+=` ${n}`;else{if(me(n,r))continue;e+=` ${n}="${g(String(r))}"`}}return e}function me(t,e){let n=t.toLowerCase();if(!ye.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 ye=new Set(["href","src","action","formaction","xlink:href"]);function g(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function ge(t){return t.startsWith("--")?t:t.replace(/([A-Z])/g,"-$1").toLowerCase()}var rt=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);export{Pt as action,se as buildVercelOutput,O as createActionHandler,oe as createCloudflareHandler,R as createRequestHandler,Qt as createServer,ae as createVercelHandler,Y as csrfMetaTag,nn as definePage,re as exportStatic,Bt as fetchActionHandler,ut as formAction,X as generateCsrfToken,rn as generateStaticPage,It as getRegisteredActions,Ct as getRevalidationHandler,L as handleActionRequest,lt as invalidatePath,Ft as nodeActionMiddleware,Ht as onRevalidate,F as renderDocument,en as renderPage,qe as renderToHydratableString,$ as renderToStream,b as renderToString,le as renderToStringAsync,tn as renderToStringWithHead,V as revalidatePath,J as revalidateTag,x as serializeState,on as server,B as setRevalidationHandler,gt as toNodeListener,dt as useAction,Ot as useFormAction,jt as useMutation,$t as useOptimistic,ct as validateCsrfToken,Kt as whatMiddleware};
25
- //# sourceMappingURL=index.min.js.map
24
+ </html>`}function on(t){return t._server=!0,t}var et=!(typeof process<"u");function nt(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"&&et&&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 he=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/;function rt(t){let e="";for(let[n,r]of Object.entries(t))if(!(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")&&!(n.startsWith("on")&&n.length>2)&&!(r===!1||r==null)){if(!he.test(n)){et&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")e+=` class="${g(String(r))}"`;else if(n==="style"&&typeof r=="object"){let o=Object.entries(r).map(([a,s])=>`${ge(a)}:${s}`).join(";");e+=` style="${g(o)}"`}else if(r===!0)n.startsWith("aria-")||n==="role"?e+=` ${n}="true"`:e+=` ${n}`;else{if(me(n,r))continue;e+=` ${n}="${g(String(r))}"`}}return e}function me(t,e){let n=t.toLowerCase();if(!ye.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 ye=new Set(["href","src","action","formaction","xlink:href"]);function g(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function ge(t){return t.startsWith("--")?t:t.replace(/([A-Z])/g,"-$1").toLowerCase()}var ot=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);export{Pt as action,se as buildVercelOutput,O as createActionHandler,oe as createCloudflareHandler,k as createRequestHandler,Qt as createServer,ae as createVercelHandler,G as csrfMetaTag,nn as definePage,re as exportStatic,Bt as fetchActionHandler,dt as formAction,Y as generateCsrfToken,rn as generateStaticPage,It as getRegisteredActions,Ct as getRevalidationHandler,L as handleActionRequest,ft as invalidatePath,Ft as nodeActionMiddleware,Ht as onRevalidate,F as renderDocument,en as renderPage,qe as renderToHydratableString,$ as renderToStream,b as renderToString,le as renderToStringAsync,tn as renderToStringWithHead,J as revalidatePath,W as revalidateTag,x as serializeState,on as server,V as setRevalidationHandler,wt as toNodeListener,lt as useAction,Ot as useFormAction,jt as useMutation,$t as useOptimistic,ut as validateCsrfToken,Kt as whatMiddleware};
@@ -1,2 +1 @@
1
1
  import{mount as C,signal as O,batch as S}from"what-core";var E=new RegExp("[<>&\\u2028\\u2029]","g"),I={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function v(e){return JSON.stringify(e).replace(E,o=>I[o.charCodeAt(0)])}var y=new Map,m=new Set,l=[],b=!1,p=new Map;function q(e,o){if(p.has(e))return p.get(e);let t={},s={};for(let[n,r]of Object.entries(o))s[n]=O(r),Object.defineProperty(t,n,{get:()=>s[n](),set:a=>s[n].set(a),enumerable:!0});return t._signals=s,t._subscribe=(n,r)=>{if(s[n])return s[n].subscribe(r)},t._batch=n=>S(n),t._getSnapshot=()=>{let n={};for(let[r,a]of Object.entries(s))n[r]=a.peek();return n},t._hydrate=n=>{S(()=>{for(let[r,a]of Object.entries(n))s[r]&&s[r].set(a)})},p.set(e,t),t}function w(e,o={}){return p.has(e)?p.get(e):q(e,o)}function J(){return v(A())}function A(){let e={};for(let[o,t]of p)e[o]=t._getSnapshot();return e}function M(e){try{let o=typeof e=="string"?JSON.parse(e):e;for(let[t,s]of Object.entries(o))w(t,s)._hydrate(s)}catch(o){console.warn("[what] Failed to hydrate island stores:",o)}}function P(e,o,t={}){y.set(e,{loader:o,mode:t.mode||"idle",media:t.media||null,priority:t.priority||0,stores:t.stores||[]})}function T({name:e,props:o={},children:t,mode:s,priority:n,stores:r}){let a=y.get(e),i=s||a?.mode||"idle",d=n??a?.priority??0,c=r||a?.stores||[];return{tag:"div",props:{"data-island":e,"data-island-mode":i,"data-island-props":JSON.stringify(o),"data-island-priority":d,"data-island-stores":JSON.stringify(c)},children:t||[],key:null,_vnode:!0}}function f(e){let o=!1;for(let t=0;t<l.length;t++)if(e.priority>l[t].priority){l.splice(t,0,e),o=!0;break}o||l.push(e),x()}function x(){if(b||l.length===0)return;b=!0;let e=l.shift();Promise.resolve(e.hydrate()).catch(o=>console.error("[what] Island hydration failed:",e.name,o)).finally(()=>{b=!1,queueMicrotask(x)})}function D(e,o=100){for(let t of l)if(t.name===e){t.priority=o,l.sort((s,n)=>n.priority-s.priority);break}}function k(){let e=document.querySelector("script[data-island-stores]");e&&M(e.textContent);let o=document.querySelectorAll("[data-island]");for(let t of o){let s=t.dataset.island,n=t.dataset.islandMode||"idle",r=JSON.parse(t.dataset.islandProps||"{}"),a=parseInt(t.dataset.islandPriority||"0",10),i=JSON.parse(t.dataset.islandStores||"[]"),d=y.get(s);if(!d){console.warn(`[what] Island "${s}" not registered`);continue}m.has(t)||N(t,d,r,n,a,s,i)}}function N(e,o,t,s,n,r,a){let i=async()=>{if(m.has(e))return;m.add(e);let d=await o.loader(),c=d.default||d,u={};for(let g of a)u[g]=w(g);let h=c({...t,...u});e.childNodes.length>0?i(h,e):C(h,e),e.removeAttribute("data-island"),e.removeAttribute("data-island-mode"),e.removeAttribute("data-island-props"),e.removeAttribute("data-island-priority"),e.removeAttribute("data-island-stores"),e.dispatchEvent(new CustomEvent("island:hydrated",{bubbles:!0,detail:{name:r,mode:s}}))};switch(s){case"load":f({name:r,priority:n+1e3,hydrate:i});break;case"idle":"requestIdleCallback"in window?requestIdleCallback(()=>{f({name:r,priority:n,hydrate:i})}):setTimeout(()=>{f({name:r,priority:n,hydrate:i})},200);break;case"visible":{new IntersectionObserver((c,u)=>{for(let h of c)if(h.isIntersecting){u.disconnect(),f({name:r,priority:n,hydrate:i});break}},{rootMargin:"200px"}).observe(e);break}case"media":{let d=window.matchMedia(o.media||"(max-width: 768px)");d.matches?f({name:r,priority:n,hydrate:i}):d.addEventListener("change",c=>{c.matches&&f({name:r,priority:n,hydrate:i})},{once:!0});break}case"action":{let d=["click","focus","mouseover","touchstart"],c=()=>{d.forEach(u=>e.removeEventListener(u,c)),f({name:r,priority:n+500,hydrate:i})};d.forEach(u=>e.addEventListener(u,c,{once:!0,passive:!0}));break}case"static":break;default:f({name:r,priority:n,hydrate:i})}}function H(e){for(let[o,t]of Object.entries(e))P(o,t.loader||t,{mode:t.mode||"idle",media:t.media,priority:t.priority||0,stores:t.stores||[]});typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",k):k())}function _(e,o){if(typeof document>"u")return;let t=document.querySelectorAll(e);for(let s of t)s.dataset.enhanced||(s.dataset.enhanced="true",o(s))}function Q(e="form[data-enhance]"){_(e,o=>{o.addEventListener("submit",async t=>{t.preventDefault();let s=new FormData(o),n=o.method.toUpperCase()||"POST",r=o.action||location.href;try{let a=document.querySelector('meta[name="csrf-token"]')||document.querySelector('meta[name="what-csrf-token"]'),i=a?a.getAttribute("content"):null,d=o.getAttribute("data-no-csrf")==="true";if(!i&&!d){console.warn('[what] Form submission blocked: no CSRF token found. Add a <meta name="csrf-token"> tag or set data-no-csrf="true" on the form to opt out.'),o.dispatchEvent(new CustomEvent("form:error",{bubbles:!0,detail:{error:new Error("Missing CSRF token")}}));return}let c={"X-Requested-With":"XMLHttpRequest"};i&&(c["X-CSRF-Token"]=i);let u=await fetch(r,{method:n,body:n==="GET"?void 0:s,headers:c});o.dispatchEvent(new CustomEvent("form:response",{bubbles:!0,detail:{response:u,ok:u.ok}}))}catch(a){o.dispatchEvent(new CustomEvent("form:error",{bubbles:!0,detail:{error:a}}))}})})}function X(){return{registered:[...y.keys()],hydrated:m.size,pending:l.length,queue:l.map(o=>({name:o.name,priority:o.priority})),stores:[...p.keys()]}}export{T as Island,H as autoIslands,D as boostIslandPriority,q as createIslandStore,_ as enhance,Q as enhanceForms,X as getIslandStatus,A as getIslandStoresSnapshot,M as hydrateIslandStores,k as hydrateIslands,P as island,J as serializeIslandStores,w as useIslandStore};
2
- //# sourceMappingURL=islands.min.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "what-server",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "What Framework - SSR, islands architecture, static generation",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -22,7 +22,7 @@
22
22
  },
23
23
  "files": [
24
24
  "src",
25
- "dist",
25
+ "dist/**/*.min.js",
26
26
  "index.d.ts"
27
27
  ],
28
28
  "sideEffects": false,
@@ -36,8 +36,8 @@
36
36
  "author": "ZVN DEV (https://zvndev.com)",
37
37
  "license": "MIT",
38
38
  "peerDependencies": {
39
- "what-core": "^0.11.0",
40
- "what-router": "^0.11.0"
39
+ "what-core": "^0.11.1",
40
+ "what-router": "^0.11.1"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "what-router": {
@@ -79,7 +79,9 @@ function safeRedirectTarget(form, headers) {
79
79
  }
80
80
 
81
81
  // Reserved form fields consumed by the framework (not passed to the action).
82
- const RESERVED_FORM_FIELDS = new Set(['_action', 'data-action', '_csrf', '_redirect']);
82
+ // `what-csrf-token` is an alias for `_csrf` matching the <meta name="what-csrf-token">
83
+ // tag SSR pages embed, so templates can reuse one name for both surfaces.
84
+ const RESERVED_FORM_FIELDS = new Set(['_action', 'data-action', '_csrf', 'what-csrf-token', '_redirect']);
83
85
 
84
86
  /**
85
87
  * Framework-agnostic action dispatcher.
@@ -103,7 +105,8 @@ const RESERVED_FORM_FIELDS = new Set(['_action', 'data-action', '_csrf', '_redir
103
105
  * X-What-Action header. `body` is the parsed form fields object.
104
106
  * - action id: `_action` (or `data-action`) hidden field, or `?action=`
105
107
  * query param (reqLike.query.action)
106
- * - CSRF token: `_csrf` hidden field
108
+ * - CSRF token: `_csrf` (or `what-csrf-token`) hidden field; an
109
+ * `x-csrf-token` HEADER wins when both are present
107
110
  * - redirect: `_redirect` hidden field (local path), else Referer, else '/'
108
111
  * The action receives ONE argument: the form fields object (reserved
109
112
  * fields stripped). Success responds 303 See Other (POST/redirect/GET);
@@ -135,10 +138,12 @@ export function createActionHandler(options = {}) {
135
138
  return htmlResponse(400, 'Missing action name (add a hidden "_action" field or ?action= query param)');
136
139
  }
137
140
 
138
- // CSRF token travels in the `_csrf` form field for plain forms; map it
139
- // to the header slot handleActionRequest validates against.
141
+ // CSRF token travels in the `_csrf` (or `what-csrf-token`) form field
142
+ // for plain forms; map it to the header slot handleActionRequest
143
+ // validates against. The header wins when both are present.
140
144
  const formHeaders = { ...headers };
141
- if (form._csrf && !formHeaders['x-csrf-token']) formHeaders['x-csrf-token'] = String(form._csrf);
145
+ const bodyToken = form._csrf ?? form['what-csrf-token'];
146
+ if (bodyToken && !formHeaders['x-csrf-token']) formHeaders['x-csrf-token'] = String(bodyToken);
142
147
 
143
148
  if (!skipCsrf && getCsrfToken && !sessionCsrfToken) {
144
149
  // CSRF is configured but this client has no token (e.g. no cookie yet).
@@ -70,7 +70,8 @@ function defaultRenderRoute(documentOptions) {
70
70
  * token for hidden form fields (cached/ISR pages rely on the cookie only,
71
71
  * so a per-user token is never baked into shared cache entries).
72
72
  * - POST /__what_action validates the client token (X-CSRF-Token header for
73
- * fetch clients, `_csrf` form field for plain HTML forms) against the cookie.
73
+ * fetch clients, `_csrf` or `what-csrf-token` form field for plain HTML
74
+ * forms — the header wins when both are present) against the cookie.
74
75
  *
75
76
  * Opt out with `csrf: false` (e.g. token-authed APIs behind another gateway),
76
77
  * or take full control by passing your own `actionHandler` — a custom handler
@@ -78,7 +79,8 @@ function defaultRenderRoute(documentOptions) {
78
79
  *
79
80
  * Plain HTML form posts (progressive enhancement, no JS) are accepted on
80
81
  * /__what_action as application/x-www-form-urlencoded — see createActionHandler
81
- * in action-handler.js for the field contract (_action, _csrf, _redirect).
82
+ * in action-handler.js for the field contract (_action, _csrf/what-csrf-token,
83
+ * _redirect).
82
84
  */
83
85
  export function createRequestHandler(options = {}) {
84
86
  const {
package/dist/actions.js DELETED
@@ -1,384 +0,0 @@
1
- // packages/server/src/actions.js
2
- import { signal, batch } from "what-core";
3
-
4
- // packages/server/src/revalidation-registry.js
5
- var _handler = null;
6
- var isDev = typeof process !== "undefined" ? true : true;
7
- async function revalidatePath(path, options) {
8
- if (_handler && _handler.revalidatePath) return _handler.revalidatePath(path, options);
9
- if (isDev) {
10
- console.warn(
11
- `[what] revalidatePath('${path}') had no effect: no cache engine is bound. Create a what-isr engine and bind it in your adapter (setRevalidationHandler).`
12
- );
13
- }
14
- }
15
- async function revalidateTag(tag, options) {
16
- if (_handler && _handler.revalidateTag) return _handler.revalidateTag(tag, options);
17
- if (isDev) {
18
- console.warn(
19
- `[what] revalidateTag('${tag}') had no effect: no cache engine is bound.`
20
- );
21
- }
22
- }
23
-
24
- // packages/server/src/actions.js
25
- var actionRegistry = /* @__PURE__ */ new Map();
26
- function getCsrfToken() {
27
- if (typeof document !== "undefined") {
28
- const meta = document.querySelector('meta[name="what-csrf-token"]');
29
- if (meta) {
30
- return meta.getAttribute("content");
31
- }
32
- const match = document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);
33
- if (match) {
34
- return decodeURIComponent(match[1]);
35
- }
36
- }
37
- return null;
38
- }
39
- function generateCsrfToken() {
40
- if (typeof crypto !== "undefined" && crypto.randomUUID) {
41
- return crypto.randomUUID();
42
- }
43
- if (typeof crypto !== "undefined" && crypto.getRandomValues) {
44
- const arr = new Uint8Array(16);
45
- crypto.getRandomValues(arr);
46
- return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
47
- }
48
- throw new Error("[what] No secure random source available for CSRF token generation");
49
- }
50
- function validateCsrfToken(requestToken, sessionToken) {
51
- if (!requestToken || !sessionToken) return false;
52
- if (requestToken.length !== sessionToken.length) return false;
53
- let result = 0;
54
- for (let i = 0; i < requestToken.length; i++) {
55
- result |= requestToken.charCodeAt(i) ^ sessionToken.charCodeAt(i);
56
- }
57
- return result === 0;
58
- }
59
- function csrfMetaTag(token) {
60
- const escaped = String(token).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
61
- return `<meta name="what-csrf-token" content="${escaped}">`;
62
- }
63
- var _actionCounter = 0;
64
- function generateActionId() {
65
- const rand = typeof crypto !== "undefined" && crypto.getRandomValues ? Array.from(crypto.getRandomValues(new Uint8Array(6)), (b) => b.toString(16).padStart(2, "0")).join("") : `c${(++_actionCounter).toString(36)}_${Date.now().toString(36)}`;
66
- return `a_${rand}`;
67
- }
68
- function action(fn, options = {}) {
69
- const id = options.id || generateActionId();
70
- const { onError, onSuccess, revalidate } = options;
71
- if (typeof window === "undefined") {
72
- actionRegistry.set(id, { fn, options });
73
- }
74
- async function callAction(...args) {
75
- if (typeof window === "undefined") {
76
- return fn(...args);
77
- }
78
- const timeout = options.timeout || 3e4;
79
- const controller = new AbortController();
80
- const timeoutId = setTimeout(() => controller.abort(), timeout);
81
- try {
82
- const csrfToken = getCsrfToken();
83
- const headers = {
84
- "Content-Type": "application/json",
85
- "X-What-Action": id
86
- };
87
- if (csrfToken) headers["X-CSRF-Token"] = csrfToken;
88
- const response = await fetch("/__what_action", {
89
- method: "POST",
90
- headers,
91
- credentials: "same-origin",
92
- signal: controller.signal,
93
- body: JSON.stringify({ args })
94
- });
95
- if (!response.ok) {
96
- const error = await response.json().catch(() => ({ message: "Action failed" }));
97
- throw new Error(error.message || "Action failed");
98
- }
99
- const result = await response.json();
100
- if (onSuccess) onSuccess(result);
101
- if (revalidate) {
102
- for (const path of revalidate) {
103
- invalidatePath(path);
104
- }
105
- }
106
- return result;
107
- } catch (error) {
108
- if (error.name === "AbortError") {
109
- const timeoutError = new Error(`Action "${id}" timed out after ${timeout}ms`);
110
- timeoutError.code = "TIMEOUT";
111
- if (onError) onError(timeoutError);
112
- throw timeoutError;
113
- }
114
- if (onError) onError(error);
115
- throw error;
116
- } finally {
117
- clearTimeout(timeoutId);
118
- }
119
- }
120
- callAction._actionId = id;
121
- callAction._isAction = true;
122
- return callAction;
123
- }
124
- function formAction(actionFn, options = {}) {
125
- const { onSuccess, onError, resetOnSuccess = true } = options;
126
- return async (formDataOrEvent) => {
127
- let formData;
128
- let form;
129
- if (formDataOrEvent instanceof Event) {
130
- formDataOrEvent.preventDefault();
131
- form = formDataOrEvent.target;
132
- formData = new FormData(form);
133
- } else {
134
- formData = formDataOrEvent;
135
- }
136
- const data = {};
137
- let hasFiles = false;
138
- for (const [key, value] of formData.entries()) {
139
- if (typeof File !== "undefined" && value instanceof File) {
140
- hasFiles = true;
141
- }
142
- if (data[key]) {
143
- if (Array.isArray(data[key])) {
144
- data[key].push(value);
145
- } else {
146
- data[key] = [data[key], value];
147
- }
148
- } else {
149
- data[key] = value;
150
- }
151
- }
152
- try {
153
- const result = hasFiles ? await actionFn(data, formData) : await actionFn(data);
154
- if (onSuccess) onSuccess(result, form);
155
- if (resetOnSuccess && form) form.reset();
156
- return result;
157
- } catch (error) {
158
- if (onError) onError(error, form);
159
- throw error;
160
- }
161
- };
162
- }
163
- function useAction(actionFn) {
164
- const isPending = signal(false);
165
- const error = signal(null);
166
- const data = signal(null);
167
- async function trigger(...args) {
168
- isPending.set(true);
169
- error.set(null);
170
- try {
171
- const result = await actionFn(...args);
172
- data.set(result);
173
- return result;
174
- } catch (e) {
175
- error.set(e);
176
- throw e;
177
- } finally {
178
- isPending.set(false);
179
- }
180
- }
181
- return {
182
- trigger,
183
- isPending: () => isPending(),
184
- error: () => error(),
185
- data: () => data(),
186
- reset: () => {
187
- error.set(null);
188
- data.set(null);
189
- }
190
- };
191
- }
192
- function useFormAction(actionFn, options = {}) {
193
- const { resetOnSuccess = true } = options;
194
- const formRef = { current: null };
195
- const actionState = useAction(formAction(actionFn, { resetOnSuccess }));
196
- function handleSubmit(e) {
197
- e.preventDefault();
198
- const formData = new FormData(e.target);
199
- formRef.current = e.target;
200
- return actionState.trigger(formData);
201
- }
202
- return {
203
- ...actionState,
204
- handleSubmit,
205
- formRef
206
- };
207
- }
208
- function useOptimistic(initialValue, reducer) {
209
- const value = signal(initialValue);
210
- const pending = signal([]);
211
- const baseValue = signal(initialValue);
212
- function addOptimistic(action2) {
213
- const optimisticValue = reducer(value.peek(), action2);
214
- batch(() => {
215
- pending.set([...pending.peek(), action2]);
216
- value.set(optimisticValue);
217
- });
218
- }
219
- function resolve(action2, serverValue) {
220
- batch(() => {
221
- pending.set(pending.peek().filter((a) => a !== action2));
222
- if (serverValue !== void 0) {
223
- baseValue.set(serverValue);
224
- let current = serverValue;
225
- for (const a of pending.peek()) {
226
- current = reducer(current, a);
227
- }
228
- value.set(current);
229
- }
230
- });
231
- }
232
- function rollback(action2, realValue) {
233
- batch(() => {
234
- const newPending = pending.peek().filter((a) => a !== action2);
235
- pending.set(newPending);
236
- const base = realValue !== void 0 ? realValue : baseValue.peek();
237
- baseValue.set(base);
238
- let current = base;
239
- for (const a of newPending) {
240
- current = reducer(current, a);
241
- }
242
- value.set(current);
243
- });
244
- }
245
- async function withOptimistic(action2, asyncFn) {
246
- addOptimistic(action2);
247
- try {
248
- const result = await asyncFn();
249
- resolve(action2, result);
250
- return result;
251
- } catch (e) {
252
- rollback(action2);
253
- throw e;
254
- }
255
- }
256
- return {
257
- value: () => value(),
258
- isPending: () => pending().length > 0,
259
- addOptimistic,
260
- resolve,
261
- rollback,
262
- withOptimistic,
263
- set: (v) => {
264
- value.set(v);
265
- baseValue.set(v);
266
- }
267
- };
268
- }
269
- var revalidationCallbacks = /* @__PURE__ */ new Map();
270
- function onRevalidate(path, callback) {
271
- if (!revalidationCallbacks.has(path)) {
272
- revalidationCallbacks.set(path, /* @__PURE__ */ new Set());
273
- }
274
- revalidationCallbacks.get(path).add(callback);
275
- return () => {
276
- revalidationCallbacks.get(path)?.delete(callback);
277
- };
278
- }
279
- function invalidatePath(path) {
280
- const callbacks = revalidationCallbacks.get(path);
281
- if (callbacks) {
282
- for (const cb of callbacks) {
283
- try {
284
- cb();
285
- } catch (e) {
286
- console.error("[what] Revalidation error:", e);
287
- }
288
- }
289
- }
290
- }
291
- function handleActionRequest(req, actionId, args, options = {}) {
292
- const { csrfToken: sessionCsrfToken, skipCsrf = false } = options;
293
- if (!skipCsrf) {
294
- if (!sessionCsrfToken) {
295
- return Promise.resolve({
296
- status: 500,
297
- body: {
298
- message: "[what] CSRF token not configured. Pass { csrfToken: sessionToken } to handleActionRequest, or { skipCsrf: true } to explicitly opt out."
299
- }
300
- });
301
- }
302
- const requestCsrfToken = req?.headers?.["x-csrf-token"] || req?.headers?.["X-CSRF-Token"];
303
- if (!validateCsrfToken(requestCsrfToken, sessionCsrfToken)) {
304
- return Promise.resolve({ status: 403, body: { message: "Invalid CSRF token" } });
305
- }
306
- }
307
- const action2 = actionRegistry.get(actionId);
308
- if (!action2) {
309
- return Promise.resolve({ status: 404, body: { message: "Action not found" } });
310
- }
311
- if (!Array.isArray(args)) {
312
- return Promise.resolve({ status: 400, body: { message: "Invalid action arguments" } });
313
- }
314
- return action2.fn(...args).then(async (result) => {
315
- const opts = action2.options || {};
316
- if (Array.isArray(opts.revalidate)) {
317
- for (const p of opts.revalidate) await revalidatePath(p);
318
- }
319
- if (Array.isArray(opts.revalidateTags)) {
320
- for (const t of opts.revalidateTags) await revalidateTag(t);
321
- }
322
- return { status: 200, body: result };
323
- }).catch((error) => {
324
- console.error(`[what] Action "${actionId}" error:`, error);
325
- return {
326
- status: 500,
327
- body: { message: "Action failed" }
328
- };
329
- });
330
- }
331
- function getRegisteredActions() {
332
- return [...actionRegistry.keys()];
333
- }
334
- function useMutation(mutationFn, options = {}) {
335
- const { onSuccess, onError, onSettled } = options;
336
- const state = {
337
- isPending: signal(false),
338
- error: signal(null),
339
- data: signal(null)
340
- };
341
- async function mutate(...args) {
342
- state.isPending.set(true);
343
- state.error.set(null);
344
- try {
345
- const result = await mutationFn(...args);
346
- state.data.set(result);
347
- if (onSuccess) onSuccess(result, ...args);
348
- return result;
349
- } catch (error) {
350
- state.error.set(error);
351
- if (onError) onError(error, ...args);
352
- throw error;
353
- } finally {
354
- state.isPending.set(false);
355
- if (onSettled) onSettled(state.data.peek(), state.error.peek(), ...args);
356
- }
357
- }
358
- return {
359
- mutate,
360
- isPending: () => state.isPending(),
361
- error: () => state.error(),
362
- data: () => state.data(),
363
- reset: () => {
364
- state.error.set(null);
365
- state.data.set(null);
366
- }
367
- };
368
- }
369
- export {
370
- action,
371
- csrfMetaTag,
372
- formAction,
373
- generateCsrfToken,
374
- getRegisteredActions,
375
- handleActionRequest,
376
- invalidatePath,
377
- onRevalidate,
378
- useAction,
379
- useFormAction,
380
- useMutation,
381
- useOptimistic,
382
- validateCsrfToken
383
- };
384
- //# sourceMappingURL=actions.js.map