what-server 0.11.6 → 0.11.8
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/actions.min.js +1 -1
- package/dist/index.min.js +9 -9
- package/dist/islands.min.js +1 -1
- package/dist/node.min.js +24 -0
- package/index.d.ts +19 -65
- package/islands.d.ts +99 -0
- package/package.json +15 -5
- package/src/action-handler.js +10 -2
- package/src/actions.js +16 -3
- package/src/adapter/core.js +19 -3
- package/src/adapter/node.js +31 -1
- package/src/adapter/static.js +15 -2
- package/src/index.js +64 -13
- package/src/islands.js +132 -29
- package/src/node.js +18 -0
- package/src/serialize.js +1 -1
package/dist/actions.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{signal as p,batch as v}from"what-core";var
|
|
1
|
+
import{signal as p,batch as v}from"what-core";var m=null,k=!(typeof process<"u");async function b(e,t){if(m&&m.revalidatePath)return m.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 S(e,t){if(m&&m.revalidateTag)return m.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 U(){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 O(e){return`<meta name="what-csrf-token" content="${String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}var T=0,x=!1;function C(){return!x&&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${(++T).toString(36)}_${Date.now().toString(36)}`}`}function N(e,t={}){let r=t.id||C(),{onError:n,onSuccess:f,revalidate:o}=t;typeof window>"u"&&A.set(r,{fn:e,options:t});async function a(...s){if(typeof window>"u")return e(...s);let i=t.timeout||3e4,u=new AbortController,c=setTimeout(()=>u.abort(),i);try{let l=P(),d={"Content-Type":"application/json","X-What-Action":r};l&&(d["X-CSRF-Token"]=l);let g=await fetch("/__what_action",{method:"POST",headers:d,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:s})});if(!g.ok){let w=await g.json().catch(()=>({message:"Action failed"}));throw new Error(w.message||"Action failed")}let h=await g.json();if(f&&f(h),o)for(let w of o)D(w);return h}catch(l){if(l.name==="AbortError"){let d=new Error(`Action "${r}" timed out after ${i}ms`);throw d.code="TIMEOUT",n&&n(d),d}throw n&&n(l),l}finally{clearTimeout(c)}}return a._actionId=r,a._isAction=!0,a}function _(e,t={}){let{onSuccess:r,onError:n,resetOnSuccess:f=!0}=t;return async o=>{let a,s;o instanceof Event?(o.preventDefault(),s=o.target,a=new FormData(s)):a=o;let i={},u=!1;for(let[c,l]of a.entries())typeof File<"u"&&l instanceof File&&(u=!0),i[c]?Array.isArray(i[c])?i[c].push(l):i[c]=[i[c],l]:i[c]=l;try{let c=u?await e(i,a):await e(i);return r&&r(c,s),f&&s&&s.reset(),c}catch(c){throw n&&n(c,s),c}}}function E(e){let t=p(!1),r=p(null),n=p(null);async function f(...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:f,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},f=E(_(e,{resetOnSuccess:r}));function o(a){a.preventDefault();let s=new FormData(a.target);return n.current=a.target,f.trigger(s)}return{...f,handleSubmit:o,formRef:n}}function M(e,t){let r=p(e),n=p([]),f=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(l=>l!==u)),c!==void 0){f.set(c);let l=c;for(let d of n.peek())l=t(l,d);r.set(l)}})}function s(u,c){v(()=>{let l=n.peek().filter(h=>h!==u);n.set(l);let d=c!==void 0?c:f.peek();f.set(d);let g=d;for(let h of l)g=t(g,h);r.set(g)})}async function i(u,c){o(u);try{let l=await c();return a(u,l),l}catch(l){throw s(u),l}}return{value:()=>r(),isPending:()=>n().length>0,addOptimistic:o,resolve:a,rollback:s,withOptimistic:i,set:u=>{r.set(u),f.set(u)}}}var y=new Map;function V(e,t){return y.has(e)||y.set(e,new Set),y.get(e).add(t),()=>{y.get(e)?.delete(t)}}function D(e){let t=y.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:f,skipCsrf:o=!1}=n;if(!o){if(!f)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 s=e?.headers?.["x-csrf-token"]||e?.headers?.["X-CSRF-Token"];if(!R(s,f))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 s=>{let i=a.options||{};if(Array.isArray(i.revalidate))for(let u of i.revalidate)await b(u);if(Array.isArray(i.revalidateTags))for(let u of i.revalidateTags)await S(u);return{status:200,body:s}}).catch(s=>(console.error(`[what] Action "${t}" error:`,s),{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 W(){return[...A.keys()]}function X(e,t={}){let{onSuccess:r,onError:n,onSettled:f}=t,o={isPending:p(!1),error:p(null),data:p(null)};async function a(...s){o.isPending.set(!0),o.error.set(null);try{let i=await e(...s);return o.data.set(i),r&&r(i,...s),i}catch(i){throw o.error.set(i),n&&n(i,...s),i}finally{o.isPending.set(!1),f&&f(o.data.peek(),o.error.peek(),...s)}}return{mutate:a,isPending:()=>o.isPending(),error:()=>o.error(),data:()=>o.data(),reset:()=>{o.error.set(null),o.data.set(null)}}}export{N as action,O as csrfMetaTag,_ as formAction,U as generateCsrfToken,W as getRegisteredActions,H as handleActionRequest,D as invalidatePath,V as onRevalidate,E as useAction,j as useFormAction,X as useMutation,M as useOptimistic,R as validateCsrfToken};
|
package/dist/index.min.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
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,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}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,"&").replace(/</g,"<").replace(/>/g,">")}</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
|
-
`),c=
|
|
3
|
-
`),
|
|
1
|
+
import{h as mt,getServerContext as gt,runWithServerContext as S,beginHeadCollection as Gt,endHeadCollection as q}from"what-core";var bt=new RegExp("[<>&\\u2028\\u2029]","g"),At={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function B(t){return JSON.stringify(t).replace(bt,e=>At[e.charCodeAt(0)])}import{mount as pe,hydrate as he,signal as ye,batch as me,getServerContext as _t}from"what-core";var Tt=new Map;function kt(t){let e=t||_t();return e&&e.islandStores instanceof Map?e.islandStores:null}function st(t){let e=typeof document<"u"?Tt:kt(t),n={};for(let[r,o]of e||[])n[r]=o._getSnapshot();return n}import{signal as A,batch as z}from"what-core";var T=null,it=!(typeof process<"u");function J(t){T=t}function Rt(){return T}async function W(t,e){if(T&&T.revalidatePath)return T.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 V(t,e){if(T&&T.revalidateTag)return T.revalidateTag(t,e);it&&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 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 K(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}var Ct=0,vt=!1;function Ot(){return!vt&&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${(++Ct).toString(36)}_${Date.now().toString(36)}`}`}function xt(t,e={}){let n=e.id||Ot(),{onError:r,onSuccess:o,revalidate:s}=e;typeof window>"u"&&X.set(n,{fn:t,options:e});async function a(...i){if(typeof window>"u")return t(...i);let c=e.timeout||3e4,d=new AbortController,u=setTimeout(()=>d.abort(),c);try{let f=Et(),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:d.signal,body:JSON.stringify({args:i})});if(!p.ok){let g=await p.json().catch(()=>({message:"Action failed"}));throw new Error(g.message||"Action failed")}let h=await p.json();if(o&&o(h),s)for(let g of s)ft(g);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(u)}}return a._actionId=n,a._isAction=!0,a}function dt(t,e={}){let{onSuccess:n,onError:r,resetOnSuccess:o=!0}=e;return async s=>{let a,i;s instanceof Event?(s.preventDefault(),i=s.target,a=new FormData(i)):a=s;let c={},d=!1;for(let[u,f]of a.entries())typeof File<"u"&&f instanceof File&&(d=!0),c[u]?Array.isArray(c[u])?c[u].push(f):c[u]=[c[u],f]:c[u]=f;try{let u=d?await t(c,a):await t(c);return n&&n(u,i),o&&i&&i.reset(),u}catch(u){throw r&&r(u,i),u}}}function ut(t){let e=A(!1),n=A(null),r=A(null);async function o(...s){e.set(!0),n.set(null);try{let a=await t(...s);return r.set(a),a}catch(a){throw n.set(a),a}finally{e.set(!1)}}return{trigger:o,isPending:()=>e(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Pt(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},o=ut(dt(t,{resetOnSuccess:n}));function s(a){a.preventDefault();let i=new FormData(a.target);return r.current=a.target,o.trigger(i)}return{...o,handleSubmit:s,formRef:r}}function $t(t,e){let n=A(t),r=A([]),o=A(t);function s(d){let u=e(n.peek(),d);z(()=>{r.set([...r.peek(),d]),n.set(u)})}function a(d,u){z(()=>{if(r.set(r.peek().filter(f=>f!==d)),u!==void 0){o.set(u);let f=u;for(let l of r.peek())f=e(f,l);n.set(f)}})}function i(d,u){z(()=>{let f=r.peek().filter(h=>h!==d);r.set(f);let l=u!==void 0?u:o.peek();o.set(l);let p=l;for(let h of f)p=e(p,h);n.set(p)})}async function c(d,u){s(d);try{let f=await u();return a(d,f),f}catch(f){throw i(d),f}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:s,resolve:a,rollback:i,withOptimistic:c,set:d=>{n.set(d),o.set(d)}}}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:s=!1}=r;if(!s){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 a=X.get(e);return a?Array.isArray(n)?a.fn(...n).then(async i=>{let c=a.options||{};if(Array.isArray(c.revalidate))for(let d of c.revalidate)await W(d);if(Array.isArray(c.revalidateTags))for(let d of c.revalidateTags)await V(d);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 Lt(t,e={}){let{onSuccess:n,onError:r,onSettled:o}=e,s={isPending:A(!1),error:A(null),data:A(null)};async function a(...i){s.isPending.set(!0),s.error.set(null);try{let c=await t(...i);return s.data.set(c),n&&n(c,...i),c}catch(c){throw s.error.set(c),r&&r(c,...i),c}finally{s.isPending.set(!1),o&&o(s.data.peek(),s.error.peek(),...i)}}return{mutate:a,isPending:()=>s.isPending(),error:()=>s.error(),data:()=>s.data(),reset:()=>{s.error.set(null),s.data.set(null)}}}var jt="/__what_action",pt=1024*1024;function Dt(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 j(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,"&").replace(/</g,"<").replace(/>/g,">")}</p></body></html>`}}function lt(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 Nt(t,e){let n=lt(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let o=new URL(r,"http://localhost"),s=lt(o.pathname+o.search);if(s)return s}catch{}return"/"}var Mt=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function $(t={}){let{getCsrfToken:e,skipCsrf:n=!1}=t;return async function(o){if((o.method||"POST").toUpperCase()!=="POST")return j(405,{message:"Method Not Allowed"});let a=Dt(o.headers),i=a["x-what-action"],c=a["content-type"]||"",d=!i&&c.includes("application/x-www-form-urlencoded"),u=n?void 0:e?await e(o):void 0;if(d){let h=o.body||{},g=h._action||h["data-action"]||o.query&&o.query.action;if(!g)return Z(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let b={...a},E=h._csrf??h["what-csrf-token"];if(E&&!b["x-csrf-token"]&&(b["x-csrf-token"]=String(E)),!n&&e&&!u)return Z(403,"Missing CSRF token");let C={};for(let[v,F]of Object.entries(h))Mt.has(v)||(C[v]=F);let R=await L({headers:b},g,[C],{csrfToken:u,skipCsrf:n});return R.status===200?{status:303,headers:{location:Nt(h,a)},body:""}:Z(R.status,R.body&&R.body.message||"Action failed")}if(!i)return j(400,{message:"Missing X-What-Action header"});if(!n&&e&&!u)return j(403,{message:"Missing CSRF token"});let l=(o.body||{}).args,p=await L({headers:a},i,l,{csrfToken:u,skipCsrf:n});return j(p.status,p.body)}}function Ft(t={}){let e=t.basePath||jt,n=$(t);return async function(o,s,a){let[i,c]=(o.url||"").split("?");if(i!==e||(o.method||"").toUpperCase()!=="POST")return a?a():void 0;let d;try{let l=await Ut(o);d=D(l,o.headers["content-type"]||"")}catch(l){s.writeHead(l.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),s.end(JSON.stringify({message:l.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let u=Object.fromEntries(new URLSearchParams(c||"")),f=await n({method:o.method,headers:o.headers,body:d,query:u});s.writeHead(f.status,f.headers),s.end(f.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 N(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(),s=[],a=0;for(;;){let{done:i,value:c}=await o.read();if(i)break;if(c){if(a+=c.byteLength,a>e){try{await o.cancel()}catch{}return{tooLarge:!0}}s.push(c)}}return{raw:Buffer.concat(s.map(i=>Buffer.from(i))).toString("utf8")}}function Ut(t){return new Promise((e,n)=>{let r=0,o=[];t.on("data",s=>{if(r+=s.length,r>pt){let a=new Error("Body too large");a.code="BODY_TOO_LARGE",n(a),t.destroy?.();return}o.push(s)}),t.on("end",()=>{if(o.length===0)return e("");e(Buffer.concat(o).toString("utf8"))}),t.on("error",n)})}function Bt(t={}){let e=$(t);return async function(n){let r={};try{let a=await N(n);if(a.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=D(a.raw,n.headers.get("content-type")||"")}catch{r={}}let o={};try{o=Object.fromEntries(new URL(n.url,"http://localhost").searchParams)}catch{}let s=await e({method:n.method,headers:n.headers,body:r,query:o});return new Response(s.body,{status:s.status,headers:s.headers})}}import{matchRoute as Jt,parseQuery as Wt}from"what-router/match";var Vt="/__what_action",zt="/__what_revalidate",G="what-csrf";function H(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 N(t);return e.tooLarge?{tooLarge:!0}:D(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function Yt(t){let e;try{e=await N(t)}catch{return{json:{}}}if(e.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(e.raw)}}catch{return{json:{}}}}function Kt(t){return async function(n){let{route:r,params:o,query:s,request:a}=n,i={default:r.component,loader:r.loader},c=n.csrfToken?{...t,csrfToken:n.csrfToken}:t;return{html:await yt(i,{params:o,query:s,request:a},c),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function Q(t={}){let{routes:e=[],cache:n,render:r,revalidateWebhook:o,document:s={},notFound:a,basePath:i="",csrf:c=!0}=t,d=c!==!1&&!t.actionHandler,u=t.actionHandler||$(d?{getCsrfToken:l=>ht(l.headers&&l.headers.cookie,G)}:{skipCsrf:!0}),f=r||Kt(s);return n&&(n.revalidatePath||n.revalidateTag)&&J({revalidatePath:n.revalidatePath,revalidateTag:n.revalidateTag}),async function(p){let h=new URL(p.url,"http://localhost"),g=h.pathname;if(i&&g.startsWith(i)&&(g=g.slice(i.length)||"/"),p.method==="POST"&&g===Vt){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 _=await u({method:"POST",headers:H(p.headers),body:y,query:Object.fromEntries(h.searchParams)});return new Response(_.body,{status:_.status,headers:_.headers})}let b=null,E=null;if(d&&(b=ht(H(p.headers).cookie,G),!b)){b=Y();let _=H(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;E=`${G}=${encodeURIComponent(b)}; Path=/; SameSite=Lax`+(_?"; Secure":"")}let C=y=>(E&&(y["set-cookie"]=E),y);if(p.method==="POST"&&g===zt&&o){let y=await Yt(p);if(y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let _=await o({headers:H(p.headers),body:y.json});return new Response(JSON.stringify(_.body),{status:_.status,headers:{"content-type":"application/json"}})}let R=Jt(g,e);if(!R){let y=a?a():"<!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:v,params:F}=R,U=v.page||{mode:v.mode||"client"},x={path:g,query:Wt(h.search),config:U,route:v,params:F,request:p};if(n&&U.mode!=="server"){x.varyHeaders=H(p.headers);let y=await n.handle(x,()=>f(x));return new Response(y.html,{status:y.status||200,headers:C({"content-type":"text/html; charset=utf-8",...y.headers||{}})})}b&&(x.csrfToken=b);let ot=await f(x),at=C({"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})}}function Zt(t={}){let e=Q(t);return{async fetch(n,r,o){return r&&(n.__env=r),o&&(n.__ctx=o),e(n)}}}function k(t){return{head:Gt(),loaderData:t,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var wt=0;function Qt(){wt=0}function qt(){return"h"+wt++}function te(t){if(typeof document>"u"&&!gt()){let e=k(void 0);return S(e,()=>te(t))}return Qt(),O(t)}function O(t){if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return m(String(t));if(typeof t=="function"&&t._signal)return`<!--$-->${O(t())}<!--/$-->`;if(typeof t=="function")try{return`<!--$-->${O(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(O).join("")}<!--/[]-->`;if(typeof t.tag=="function"){let c=qt(),d=t.tag({...t.props,children:t.children}),u=O(d);return ee(u,c)}let{tag:e,props:n,children:r}=t;et(e);let o=nt(n||{}),s=`<${e}${o}>`;if(rt.has(e))return s;let a=tt(n),i=a!=null?String(a):r.map(O).join("");return`${s}${i}</${e}>`}function ee(t,e){let n=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],o=n[2],s=r.length+1+o.length;return t.slice(0,s)+` data-hk="${e}"`+t.slice(s)}return t}function w(t){if(typeof document>"u"&&!gt()){let c=k(void 0);return S(c,()=>w(t))}if(t==null||t===!1||t===!0)return"";if(typeof t=="string"||typeof t=="number")return m(String(t));if(typeof t=="function"&&t._signal)return w(t());if(typeof t=="function")try{return w(t())}catch{return typeof process<"u",""}if(Array.isArray(t))return t.map(w).join("");if(t.tag==="__suspense")try{return(t.children||[]).map(w).join("")}catch(c){if(c&&typeof c.then=="function")return w(t.props&&t.props.fallback);throw c}if(typeof t.tag=="function"){let c=t.tag({...t.props,children:t.children});return w(c)}let{tag:e,props:n,children:r}=t;et(e);let o=nt(n||{}),s=`<${e}${o}>`;if(rt.has(e))return s;let a=tt(n),i=a!=null?String(a):r.map(w).join("");return`${s}${i}</${e}>`}function je(t){let e=k(void 0);return{body:S(e,()=>w(t)),head:q(e.head)}}async function De(t,e={}){let n=t.default||t,r=typeof t.loader=="function"?await t.loader(e):void 0,o=k(r),s=e.params||{};return{body:S(o,()=>w(mt(n,{...s,loaderData:r}))),head:q(o.head),loaderData:r}}var St=12;async function ne(t,e){e||(e=k(void 0));let n="";for(let o=0;o<St;o++){n=S(e,()=>w(t));let s=[...e.resources.values()].filter(a=>a.status==="pending").map(a=>a.promise);if(s.length===0)break;await Promise.all(s)}let r={};for(let[o,s]of e.resources)s.status==="ready"&&(r[o]=s.value);return{body:n,head:q(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function yt(t,e={},n={}){let r=t.default||t,o=typeof t.loader=="function"?await t.loader(e):void 0,s=k(o),a=e.params||{},{body:i,head:c,resources:d}=await ne(mt(r,{...a,loaderData:o}),s),u={loaderData:o??null,resources:d,islandStores:st(s)};return re({body:i,head:c,payload:u,options:n})}function re({body:t,head:e,payload:n,options:r={}}){let o=r.lang||"en",s=`<script id="__what_data" type="application/json">${B(n)}<\/script>`,a=r.clientEntry?`<script type="module" src="${m(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?K(r.csrfToken):"")+(r.head||""),d=r.bodyClass?` class="${m(r.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${m(o)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${e||""}${c}</head><body${d}>${t}${s}${a}</body></html>`}async function*I(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 m(String(t));return}if(typeof t=="function"&&t._signal){let a=S(e,()=>t());yield*I(a,e);return}if(typeof t=="function"){try{let a=S(e,()=>t());yield*I(a,e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let a of t)yield*I(a,e);return}if(t.tag==="__suspense"){let a=null;for(let i=0;i<St&&a===null;i++){let c=null;try{a=S(e,()=>(t.children||[]).map(w).join(""))}catch(d){if(d&&typeof d.then=="function")c=d;else throw d}if(a===null){let d=[...e.resources.values()].filter(u=>u.status==="pending").map(u=>u.promise);await Promise.all([c,...d].filter(Boolean))}}a===null&&(a=S(e,()=>w(t.props&&t.props.fallback))),yield a;return}if(typeof t.tag=="function"){try{let a=S(e,()=>t.tag({...t.props,children:t.children})),i=a instanceof Promise?await a:a;yield*I(i,e)}catch(a){typeof process<"u",yield M?`<!-- SSR Error: ${m(a.message||"Component error")} -->`:"<!-- SSR Error -->"}return}let{tag:n,props:r,children:o}=t;et(n);let s=nt(r||{});if(yield`<${n}${s}>`,!rt.has(n)){let a=tt(r);if(a!=null)yield String(a);else for(let i of o)yield*I(i,e);yield`</${n}>`}}function Ne(t){return{mode:"static",...t}}function Me(t,e={}){let n=k(e),r=S(n,()=>{let s=t.component(e);return w(s)}),o=t.islands||[];return oe({title:t.title||"",meta:t.meta||{},body:r,islands:o,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function oe({title:t,meta:e,body:n,islands:r,scripts:o,styles:s,mode:a}){let i=Object.entries(e).map(([l,p])=>`<meta name="${m(l)}" content="${m(p)}">`).join(`
|
|
2
|
+
`),c=s.map(l=>`<link rel="stylesheet" href="${m(l)}">`).join(`
|
|
3
|
+
`),d=r.length>0?`
|
|
4
4
|
<script type="module">
|
|
5
5
|
import { hydrateIslands } from '/@what/islands.js';
|
|
6
6
|
hydrateIslands();
|
|
7
|
-
<\/script>`:"",
|
|
8
|
-
`),
|
|
7
|
+
<\/script>`:"",u=o.map(l=>`<script type="module" src="${m(l)}"><\/script>`).join(`
|
|
8
|
+
`),f=a==="client"?`
|
|
9
9
|
<script type="module" src="/@what/client.js"><\/script>`:"";return`<!DOCTYPE html>
|
|
10
10
|
<html lang="en">
|
|
11
11
|
<head>
|
|
12
12
|
<meta charset="UTF-8">
|
|
13
13
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
14
14
|
${i}
|
|
15
|
-
<title>${
|
|
15
|
+
<title>${m(t)}</title>
|
|
16
16
|
${c}
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="app">${n}</div>
|
|
20
|
-
${u}
|
|
21
20
|
${d}
|
|
22
|
-
${
|
|
21
|
+
${u}
|
|
22
|
+
${f}
|
|
23
23
|
</body>
|
|
24
|
-
</html>`}function
|
|
24
|
+
</html>`}function Fe(t){return t._server=!0,t}var M=!(typeof process<"u");function tt(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"&&M&&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 ae=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,se=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function et(t){if(typeof t!="string"||!se.test(t))throw new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(t)}`)}function nt(t){let e="";for(let[n,r]of Object.entries(t)){if(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")continue;let o=n.toLowerCase();if(!(o.startsWith("on")&&n.length>2)&&!(r===!1||r==null)){if(!ae.test(n)){M&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(de.has(o)){M&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")e+=` class="${m(String(r))}"`;else if(n==="style"&&typeof r=="object"){let s=Object.entries(r).map(([a,i])=>`${ue(a)}:${i}`).join(";");e+=` style="${m(s)}"`}else if(r===!0)n.startsWith("aria-")||n==="role"?e+=` ${n}="true"`:e+=` ${n}`;else{if(ie(n,r))continue;e+=` ${n}="${m(String(r))}"`}}}return e}function ie(t,e){let n=t.toLowerCase();if(!ce.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 ce=new Set(["href","src","action","formaction","data","ping","xlink:href"]),de=new Set(["srcdoc"]);function m(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function ue(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{xt as action,$ as createActionHandler,Zt as createCloudflareHandler,Q as createRequestHandler,K as csrfMetaTag,Ne as definePage,Bt as fetchActionHandler,dt as formAction,Y as generateCsrfToken,Me as generateStaticPage,It as getRegisteredActions,Rt as getRevalidationHandler,L as handleActionRequest,ft as invalidatePath,Ft as nodeActionMiddleware,Ht as onRevalidate,yt as renderDocument,De as renderPage,te as renderToHydratableString,I as renderToStream,w as renderToString,ne as renderToStringAsync,je as renderToStringWithHead,W as revalidatePath,V as revalidateTag,B as serializeState,Fe as server,J as setRevalidationHandler,ut as useAction,Pt as useFormAction,Lt as useMutation,$t as useOptimistic,ct as validateCsrfToken};
|
package/dist/islands.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mount as
|
|
1
|
+
import{mount as P,hydrate as R,signal as q,batch as E,getServerContext as N}from"what-core";var _=new RegExp("[<>&\\u2028\\u2029]","g"),A={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function x(e){return JSON.stringify(e).replace(_,r=>A[r.charCodeAt(0)])}var S=new Map,b=new Set,f=[],v=!1,w=new Map,p=new Map;function g(e){if(typeof structuredClone=="function")try{return structuredClone(e)}catch{}return Array.isArray(e)?e.map(g):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([r,t])=>[r,g(t)])):e}function h(e,r,t){if(e.has(r))return e.get(r);let n={},s={};for(let[o,a]of Object.entries(g(t)))s[o]=q(a),Object.defineProperty(n,o,{get:()=>s[o](),set:i=>s[o].set(i),enumerable:!0});return n._signals=s,n._subscribe=(o,a)=>{if(s[o])return s[o].subscribe(a)},n._batch=o=>E(o),n._getSnapshot=()=>{let o={};for(let[a,i]of Object.entries(s))o[a]=i.peek();return o},n._hydrate=o=>{E(()=>{for(let[a,i]of Object.entries(o))s[a]&&s[a].set(i)})},e.set(r,n),n}function y(e){let r=e||N();return r&&r.islandStores instanceof Map?r.islandStores:null}function I(e,r){if(p.has(e))return p.get(e).handle;let t={initialState:g(r),handle:null},n=()=>{let s=y();if(!s)throw new Error(`[what-server] Island store "${e}" was accessed outside an active server render. Read or write module-scoped island stores from a component rendered by renderDocument/renderPage.`);return h(s,e,t.initialState)};return t.handle=new Proxy({},{get(s,o){return Reflect.get(n(),o)},set(s,o,a){return Reflect.set(n(),o,a)},has(s,o){return Reflect.has(n(),o)},ownKeys(){return Reflect.ownKeys(n())},getOwnPropertyDescriptor(s,o){let a=Reflect.getOwnPropertyDescriptor(n(),o);return a?{...a,configurable:!0}:void 0}}),p.set(e,t),t.handle}function X(e,r){if(typeof document<"u")return h(w,e,r);let t=y();if(t){let n=p.get(e);return h(t,e,n?.initialState??r)}return I(e,r)}function O(e,r={}){if(typeof document<"u")return h(w,e,r);let t=y();if(t){let n=p.get(e);return h(t,e,n?.initialState??r)}return I(e,r)}function z(){return x(j())}function j(e){let r=typeof document<"u"?w:y(e),t={};for(let[n,s]of r||[])t[n]=s._getSnapshot();return t}function D(e){try{let r=typeof e=="string"?JSON.parse(e):e;for(let[t,n]of Object.entries(r))O(t,n)._hydrate(n)}catch(r){console.warn("[what] Failed to hydrate island stores:",r)}}function F(e,r,t={}){S.set(e,{loader:r,mode:t.mode||"idle",media:t.media||null,priority:t.priority||0,stores:t.stores||[]})}function K({name:e,props:r={},children:t,mode:n,priority:s,stores:o}){let a=S.get(e),i=n||a?.mode||"idle",d=s??a?.priority??0,c=o||a?.stores||[];return{tag:"div",props:{"data-island":e,"data-island-mode":i,"data-island-props":JSON.stringify(r),"data-island-priority":d,"data-island-stores":JSON.stringify(c)},children:t||[],key:null,_vnode:!0}}function l(e){let r=!1;for(let t=0;t<f.length;t++)if(e.priority>f[t].priority){f.splice(t,0,e),r=!0;break}r||f.push(e),M()}function M(){if(v||f.length===0)return;v=!0;let e=f.shift();Promise.resolve(e.hydrate()).catch(r=>console.error("[what] Island hydration failed:",e.name,r)).finally(()=>{v=!1,queueMicrotask(M)})}function U(e,r=100){for(let t of f)if(t.name===e){t.priority=r,f.sort((n,s)=>s.priority-n.priority);break}}function C(){let e=document.getElementById("__what_data");if(e)try{let t=JSON.parse(e.textContent||"{}");t&&t.islandStores&&D(t.islandStores)}catch(t){console.warn("[what] Failed to parse hydration payload:",t)}let r=document.querySelectorAll("[data-island]");for(let t of r){let n=t.dataset.island,s=t.dataset.islandMode||"idle",o=JSON.parse(t.dataset.islandProps||"{}"),a=parseInt(t.dataset.islandPriority||"0",10),i=JSON.parse(t.dataset.islandStores||"[]"),d=S.get(n);if(!d){console.warn(`[what] Island "${n}" not registered`);continue}b.has(t)||J(t,d,o,s,a,n,i)}}function J(e,r,t,n,s,o,a){let i=async()=>{if(b.has(e))return;b.add(e);let d=await r.loader(),c=d.default||d,u={};for(let k of a)u[k]=O(k);let m=c({...t,...u});e.childNodes.length>0?R(m,e):P(m,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:o,mode:n}}))};switch(n){case"load":l({name:o,priority:s+1e3,hydrate:i});break;case"idle":"requestIdleCallback"in window?requestIdleCallback(()=>{l({name:o,priority:s,hydrate:i})}):setTimeout(()=>{l({name:o,priority:s,hydrate:i})},200);break;case"visible":{new IntersectionObserver((c,u)=>{for(let m of c)if(m.isIntersecting){u.disconnect(),l({name:o,priority:s,hydrate:i});break}},{rootMargin:"200px"}).observe(e);break}case"media":{let d=window.matchMedia(r.media||"(max-width: 768px)");d.matches?l({name:o,priority:s,hydrate:i}):d.addEventListener("change",c=>{c.matches&&l({name:o,priority:s,hydrate:i})},{once:!0});break}case"action":{let d=["click","focus","mouseover","touchstart"],c=()=>{d.forEach(u=>e.removeEventListener(u,c)),l({name:o,priority:s+500,hydrate:i})};d.forEach(u=>e.addEventListener(u,c,{once:!0,passive:!0}));break}case"static":break;default:l({name:o,priority:s,hydrate:i})}}function $(e){for(let[r,t]of Object.entries(e))F(r,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",C):C())}function L(e,r){if(typeof document>"u")return;let t=document.querySelectorAll(e);for(let n of t)n.dataset.enhanced||(n.dataset.enhanced="true",r(n))}function B(e="form[data-enhance]"){L(e,r=>{r.addEventListener("submit",async t=>{t.preventDefault();let n=new FormData(r),s=r.method.toUpperCase()||"POST",o=r.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=r.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.'),r.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(o,{method:s,body:s==="GET"?void 0:n,headers:c});r.dispatchEvent(new CustomEvent("form:response",{bubbles:!0,detail:{response:u,ok:u.ok}}))}catch(a){r.dispatchEvent(new CustomEvent("form:error",{bubbles:!0,detail:{error:a}}))}})})}function G(){let e=typeof document<"u"?[...w.keys()]:[...y()?.keys()||p.keys()];return{registered:[...S.keys()],hydrated:b.size,pending:f.length,queue:f.map(t=>({name:t.name,priority:t.priority})),stores:e}}export{K as Island,$ as autoIslands,U as boostIslandPriority,X as createIslandStore,L as enhance,B as enhanceForms,G as getIslandStatus,j as getIslandStoresSnapshot,D as hydrateIslandStores,C as hydrateIslands,F as island,z as serializeIslandStores,O as useIslandStore};
|
package/dist/node.min.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import{AsyncLocalStorage as Pe}from"node:async_hooks";import{__installServerContextStorage as $e}from"what-core";import{h as St,getServerContext as bt,runWithServerContext as b,beginHeadCollection as ae,endHeadCollection as nt}from"what-core";var Ct=new RegExp("[<>&\\u2028\\u2029]","g"),xt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function $(t){return JSON.stringify(t).replace(Ct,e=>xt[e.charCodeAt(0)])}import{mount as Ie,hydrate as Ne,signal as Le,batch as De,getServerContext as Ot}from"what-core";var Pt=new Map;function $t(t){let e=t||Ot();return e&&e.islandStores instanceof Map?e.islandStores:null}function lt(t){let e=typeof document<"u"?Pt:$t(t),n={};for(let[r,o]of e||[])n[r]=o._getSnapshot();return n}import{signal as _,batch as K}from"what-core";var R=null,ft=!(typeof process<"u");function Y(t){R=t}function Ht(){return R}async function X(t,e){if(R&&R.revalidatePath)return R.revalidatePath(t,e);ft&&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 G(t,e){if(R&&R.revalidateTag)return R.revalidateTag(t,e);ft&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var Z=new Map;function jt(){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 Q(){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 pt(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 q(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}var It=0,Nt=!1;function Lt(){return!Nt&&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${(++It).toString(36)}_${Date.now().toString(36)}`}`}function Dt(t,e={}){let n=e.id||Lt(),{onError:r,onSuccess:o,revalidate:s}=e;typeof window>"u"&&Z.set(n,{fn:t,options:e});async function a(...i){if(typeof window>"u")return t(...i);let c=e.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let l=jt(),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 y=await p.json().catch(()=>({message:"Action failed"}));throw new Error(y.message||"Action failed")}let h=await p.json();if(o&&o(h),s)for(let y of s)mt(y);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 a._actionId=n,a._isAction=!0,a}function ht(t,e={}){let{onSuccess:n,onError:r,resetOnSuccess:o=!0}=e;return async s=>{let a,i;s instanceof Event?(s.preventDefault(),i=s.target,a=new FormData(i)):a=s;let c={},u=!1;for(let[d,l]of a.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,a):await t(c);return n&&n(d,i),o&&i&&i.reset(),d}catch(d){throw r&&r(d,i),d}}}function yt(t){let e=_(!1),n=_(null),r=_(null);async function o(...s){e.set(!0),n.set(null);try{let a=await t(...s);return r.set(a),a}catch(a){throw n.set(a),a}finally{e.set(!1)}}return{trigger:o,isPending:()=>e(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Mt(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},o=yt(ht(t,{resetOnSuccess:n}));function s(a){a.preventDefault();let i=new FormData(a.target);return r.current=a.target,o.trigger(i)}return{...o,handleSubmit:s,formRef:r}}function Ft(t,e){let n=_(t),r=_([]),o=_(t);function s(u){let d=e(n.peek(),u);K(()=>{r.set([...r.peek(),u]),n.set(d)})}function a(u,d){K(()=>{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){K(()=>{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){s(u);try{let l=await d();return a(u,l),l}catch(l){throw i(u),l}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:s,resolve:a,rollback:i,withOptimistic:c,set:u=>{n.set(u),o.set(u)}}}var H=new Map;function Ut(t,e){return H.has(t)||H.set(t,new Set),H.get(t).add(e),()=>{H.get(t)?.delete(e)}}function mt(t){let e=H.get(t);if(e)for(let n of e)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function D(t,e,n,r={}){let{csrfToken:o,skipCsrf:s=!1}=r;if(!s){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(!pt(i,o))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let a=Z.get(e);return a?Array.isArray(n)?a.fn(...n).then(async i=>{let c=a.options||{};if(Array.isArray(c.revalidate))for(let u of c.revalidate)await X(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await G(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 Bt(){return[...Z.keys()]}function Jt(t,e={}){let{onSuccess:n,onError:r,onSettled:o}=e,s={isPending:_(!1),error:_(null),data:_(null)};async function a(...i){s.isPending.set(!0),s.error.set(null);try{let c=await t(...i);return s.data.set(c),n&&n(c,...i),c}catch(c){throw s.error.set(c),r&&r(c,...i),c}finally{s.isPending.set(!1),o&&o(s.data.peek(),s.error.peek(),...i)}}return{mutate:a,isPending:()=>s.isPending(),error:()=>s.error(),data:()=>s.data(),reset:()=>{s.error.set(null),s.data.set(null)}}}var Vt="/__what_action",j=1024*1024;function Wt(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 M(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function tt(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,"&").replace(/</g,"<").replace(/>/g,">")}</p></body></html>`}}function gt(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 zt(t,e){let n=gt(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let o=new URL(r,"http://localhost"),s=gt(o.pathname+o.search);if(s)return s}catch{}return"/"}var Yt=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function I(t={}){let{getCsrfToken:e,skipCsrf:n=!1}=t;return async function(o){if((o.method||"POST").toUpperCase()!=="POST")return M(405,{message:"Method Not Allowed"});let a=Wt(o.headers),i=a["x-what-action"],c=a["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=n?void 0:e?await e(o):void 0;if(u){let h=o.body||{},y=h._action||h["data-action"]||o.query&&o.query.action;if(!y)return tt(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let S={...a},v=h._csrf??h["what-csrf-token"];if(v&&!S["x-csrf-token"]&&(S["x-csrf-token"]=String(v)),!n&&e&&!d)return tt(403,"Missing CSRF token");let C={};for(let[x,W]of Object.entries(h))Yt.has(x)||(C[x]=W);let E=await D({headers:S},y,[C],{csrfToken:d,skipCsrf:n});return E.status===200?{status:303,headers:{location:zt(h,a)},body:""}:tt(E.status,E.body&&E.body.message||"Action failed")}if(!i)return M(400,{message:"Missing X-What-Action header"});if(!n&&e&&!d)return M(403,{message:"Missing CSRF token"});let f=(o.body||{}).args,p=await D({headers:a},i,f,{csrfToken:d,skipCsrf:n});return M(p.status,p.body)}}function Xt(t={}){let e=t.basePath||Vt,n=I(t);return async function(o,s,a){let[i,c]=(o.url||"").split("?");if(i!==e||(o.method||"").toUpperCase()!=="POST")return a?a():void 0;let u;try{let f=await Gt(o);u=F(f,o.headers["content-type"]||"")}catch(f){s.writeHead(f.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),s.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});s.writeHead(l.status,l.headers),s.end(l.body)}}function F(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 U(t,e=j){let n=Number(t.headers.get("content-length"));if(Number.isFinite(n)&&n>e)return{tooLarge:!0};let r=t.body;if(!r||typeof r.getReader!="function"){let i=await t.text();return Buffer.byteLength(i,"utf8")>e?{tooLarge:!0}:{raw:i}}let o=r.getReader(),s=[],a=0;for(;;){let{done:i,value:c}=await o.read();if(i)break;if(c){if(a+=c.byteLength,a>e){try{await o.cancel()}catch{}return{tooLarge:!0}}s.push(c)}}return{raw:Buffer.concat(s.map(i=>Buffer.from(i))).toString("utf8")}}function Gt(t){return new Promise((e,n)=>{let r=0,o=[];t.on("data",s=>{if(r+=s.length,r>j){let a=new Error("Body too large");a.code="BODY_TOO_LARGE",n(a),t.destroy?.();return}o.push(s)}),t.on("end",()=>{if(o.length===0)return e("");e(Buffer.concat(o).toString("utf8"))}),t.on("error",n)})}function Kt(t={}){let e=I(t);return async function(n){let r={};try{let a=await U(n);if(a.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=F(a.raw,n.headers.get("content-type")||"")}catch{r={}}let o={};try{o=Object.fromEntries(new URL(n.url,"http://localhost").searchParams)}catch{}let s=await e({method:n.method,headers:n.headers,body:r,query:o});return new Response(s.body,{status:s.status,headers:s.headers})}}import{matchRoute as Zt,parseQuery as Qt}from"what-router/match";var qt="/__what_action",te="/__what_revalidate",et="what-csrf";function N(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((n,r)=>{e[r.toLowerCase()]=n}),e}function wt(t,e){if(!t)return null;let n=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function ee(t){try{let e=await U(t);return e.tooLarge?{tooLarge:!0}:F(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function ne(t){let e;try{e=await U(t)}catch{return{json:{}}}if(e.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(e.raw)}}catch{return{json:{}}}}function re(t){return async function(n){let{route:r,params:o,query:s,request:a}=n,i={default:r.component,loader:r.loader},c=n.csrfToken?{...t,csrfToken:n.csrfToken}:t;return{html:await B(i,{params:o,query:s,request:a},c),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function T(t={}){let{routes:e=[],cache:n,render:r,revalidateWebhook:o,document:s={},notFound:a,basePath:i="",csrf:c=!0}=t,u=c!==!1&&!t.actionHandler,d=t.actionHandler||I(u?{getCsrfToken:f=>wt(f.headers&&f.headers.cookie,et)}:{skipCsrf:!0}),l=r||re(s);return n&&(n.revalidatePath||n.revalidateTag)&&Y({revalidatePath:n.revalidatePath,revalidateTag:n.revalidateTag}),async function(p){let h=new URL(p.url,"http://localhost"),y=h.pathname;if(i&&y.startsWith(i)&&(y=y.slice(i.length)||"/"),p.method==="POST"&&y===qt){let m=await ee(p);if(m&&m.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await d({method:"POST",headers:N(p.headers),body:m,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let S=null,v=null;if(u&&(S=wt(N(p.headers).cookie,et),!S)){S=Q();let A=N(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;v=`${et}=${encodeURIComponent(S)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let C=m=>(v&&(m["set-cookie"]=v),m);if(p.method==="POST"&&y===te&&o){let m=await ne(p);if(m.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await o({headers:N(p.headers),body:m.json});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let E=Zt(y,e);if(!E){let m=a?a():"<!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:x,params:W}=E,z=x.page||{mode:x.mode||"client"},P={path:y,query:Qt(h.search),config:z,route:x,params:W,request:p};if(n&&z.mode!=="server"){P.varyHeaders=N(p.headers);let m=await n.handle(P,()=>l(P));return new Response(m.html,{status:m.status||200,headers:C({"content-type":"text/html; charset=utf-8",...m.headers||{}})})}S&&(P.csrfToken=S);let ut=await l(P),dt=C({"content-type":"text/html; charset=utf-8"});return z.mode==="server"&&(dt["Cache-Control"]="private, no-store"),new Response(ut.html,{status:ut.status||200,headers:dt})}}function oe(t={}){let e=T(t);return{async fetch(n,r,o){return r&&(n.__env=r),o&&(n.__ctx=o),e(n)}}}function k(t){return{head:ae(),loaderData:t,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var _t=0;function se(){_t=0}function ie(){return"h"+_t++}function ce(t){if(typeof document>"u"&&!bt()){let e=k(void 0);return b(e,()=>ce(t))}return se(),O(t)}function O(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`<!--$-->${O(t())}<!--/$-->`;if(typeof t=="function")try{return`<!--$-->${O(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(O).join("")}<!--/[]-->`;if(typeof t.tag=="function"){let c=ie(),u=t.tag({...t.props,children:t.children}),d=O(u);return ue(d,c)}let{tag:e,props:n,children:r}=t;ot(e);let o=at(n||{}),s=`<${e}${o}>`;if(st.has(e))return s;let a=rt(n),i=a!=null?String(a):r.map(O).join("");return`${s}${i}</${e}>`}function ue(t,e){let n=t.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],o=n[2],s=r.length+1+o.length;return t.slice(0,s)+` data-hk="${e}"`+t.slice(s)}return t}function w(t){if(typeof document>"u"&&!bt()){let c=k(void 0);return b(c,()=>w(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 w(t());if(typeof t=="function")try{return w(t())}catch{return typeof process<"u",""}if(Array.isArray(t))return t.map(w).join("");if(t.tag==="__suspense")try{return(t.children||[]).map(w).join("")}catch(c){if(c&&typeof c.then=="function")return w(t.props&&t.props.fallback);throw c}if(typeof t.tag=="function"){let c=t.tag({...t.props,children:t.children});return w(c)}let{tag:e,props:n,children:r}=t;ot(e);let o=at(n||{}),s=`<${e}${o}>`;if(st.has(e))return s;let a=rt(n),i=a!=null?String(a):r.map(w).join("");return`${s}${i}</${e}>`}function on(t){let e=k(void 0);return{body:b(e,()=>w(t)),head:nt(e.head)}}async function an(t,e={}){let n=t.default||t,r=typeof t.loader=="function"?await t.loader(e):void 0,o=k(r),s=e.params||{};return{body:b(o,()=>w(St(n,{...s,loaderData:r}))),head:nt(o.head),loaderData:r}}var At=12;async function de(t,e){e||(e=k(void 0));let n="";for(let o=0;o<At;o++){n=b(e,()=>w(t));let s=[...e.resources.values()].filter(a=>a.status==="pending").map(a=>a.promise);if(s.length===0)break;await Promise.all(s)}let r={};for(let[o,s]of e.resources)s.status==="ready"&&(r[o]=s.value);return{body:n,head:nt(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function B(t,e={},n={}){let r=t.default||t,o=typeof t.loader=="function"?await t.loader(e):void 0,s=k(o),a=e.params||{},{body:i,head:c,resources:u}=await de(St(r,{...a,loaderData:o}),s),d={loaderData:o??null,resources:u,islandStores:lt(s)};return le({body:i,head:c,payload:d,options:n})}function le({body:t,head:e,payload:n,options:r={}}){let o=r.lang||"en",s=`<script id="__what_data" type="application/json">${$(n)}<\/script>`,a=r.clientEntry?`<script type="module" src="${g(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?q(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}${s}${a}</body></html>`}async function*L(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 g(String(t));return}if(typeof t=="function"&&t._signal){let a=b(e,()=>t());yield*L(a,e);return}if(typeof t=="function"){try{let a=b(e,()=>t());yield*L(a,e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let a of t)yield*L(a,e);return}if(t.tag==="__suspense"){let a=null;for(let i=0;i<At&&a===null;i++){let c=null;try{a=b(e,()=>(t.children||[]).map(w).join(""))}catch(u){if(u&&typeof u.then=="function")c=u;else throw u}if(a===null){let u=[...e.resources.values()].filter(d=>d.status==="pending").map(d=>d.promise);await Promise.all([c,...u].filter(Boolean))}}a===null&&(a=b(e,()=>w(t.props&&t.props.fallback))),yield a;return}if(typeof t.tag=="function"){try{let a=b(e,()=>t.tag({...t.props,children:t.children})),i=a instanceof Promise?await a:a;yield*L(i,e)}catch(a){typeof process<"u",yield J?`<!-- SSR Error: ${g(a.message||"Component error")} -->`:"<!-- SSR Error -->"}return}let{tag:n,props:r,children:o}=t;ot(n);let s=at(r||{});if(yield`<${n}${s}>`,!st.has(n)){let a=rt(r);if(a!=null)yield String(a);else for(let i of o)yield*L(i,e);yield`</${n}>`}}function sn(t){return{mode:"static",...t}}function cn(t,e={}){let n=k(e),r=b(n,()=>{let s=t.component(e);return w(s)}),o=t.islands||[];return fe({title:t.title||"",meta:t.meta||{},body:r,islands:o,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function fe({title:t,meta:e,body:n,islands:r,scripts:o,styles:s,mode:a}){let i=Object.entries(e).map(([f,p])=>`<meta name="${g(f)}" content="${g(p)}">`).join(`
|
|
2
|
+
`),c=s.map(f=>`<link rel="stylesheet" href="${g(f)}">`).join(`
|
|
3
|
+
`),u=r.length>0?`
|
|
4
|
+
<script type="module">
|
|
5
|
+
import { hydrateIslands } from '/@what/islands.js';
|
|
6
|
+
hydrateIslands();
|
|
7
|
+
<\/script>`:"",d=o.map(f=>`<script type="module" src="${g(f)}"><\/script>`).join(`
|
|
8
|
+
`),l=a==="client"?`
|
|
9
|
+
<script type="module" src="/@what/client.js"><\/script>`:"";return`<!DOCTYPE html>
|
|
10
|
+
<html lang="en">
|
|
11
|
+
<head>
|
|
12
|
+
<meta charset="UTF-8">
|
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
14
|
+
${i}
|
|
15
|
+
<title>${g(t)}</title>
|
|
16
|
+
${c}
|
|
17
|
+
</head>
|
|
18
|
+
<body>
|
|
19
|
+
<div id="app">${n}</div>
|
|
20
|
+
${u}
|
|
21
|
+
${d}
|
|
22
|
+
${l}
|
|
23
|
+
</body>
|
|
24
|
+
</html>`}function un(t){return t._server=!0,t}var J=!(typeof process<"u");function rt(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"&&J&&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 pe=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,he=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function ot(t){if(typeof t!="string"||!he.test(t))throw new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(t)}`)}function at(t){let e="";for(let[n,r]of Object.entries(t)){if(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")continue;let o=n.toLowerCase();if(!(o.startsWith("on")&&n.length>2)&&!(r===!1||r==null)){if(!pe.test(n)){J&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(ge.has(o)){J&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")e+=` class="${g(String(r))}"`;else if(n==="style"&&typeof r=="object"){let s=Object.entries(r).map(([a,i])=>`${we(a)}:${i}`).join(";");e+=` style="${g(s)}"`}else if(r===!0)n.startsWith("aria-")||n==="role"?e+=` ${n}="true"`:e+=` ${n}`;else{if(ye(n,r))continue;e+=` ${n}="${g(String(r))}"`}}}return e}function ye(t,e){let n=t.toLowerCase();if(!me.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 me=new Set(["href","src","action","formaction","data","ping","xlink:href"]),ge=new Set(["srcdoc"]);function g(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function we(t){return t.startsWith("--")?t:t.replace(/([A-Z])/g,"-$1").toLowerCase()}var st=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);import Se from"node:http";var it=Symbol("what.bodyTooLarge"),Rt=()=>new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});async function Tt(t){let n=`http://${t.headers.host||"localhost"}${t.url}`,r=new Headers;for(let[s,a]of Object.entries(t.headers))a!=null&&r.set(s,Array.isArray(a)?a.join(", "):String(a));let o;if(t.method!=="GET"&&t.method!=="HEAD"){let s=Number(t.headers["content-length"]),a=Number.isFinite(s)&&s>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 it;i.length&&(o=Buffer.concat(i))}return new Request(n,{method:t.method,headers:r,body:o})}async function V(t,e){t.statusCode=e.status,e.headers.forEach((r,o)=>t.setHeader(o,r));let n=await e.text();t.end(n)}function kt(t){return async function(n,r){try{let o=await Tt(n);if(o===it)return await V(r,Rt());let s=await t(o);await V(r,s)}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 be(t={}){let e=T(t);return async function(r,o,s){let a=await Tt(r);if(a===it)return await V(o,Rt());let i=await e(a);if(i.status===404&&typeof s=="function")return s();await V(o,i)}}function _e(t={}){let e=T(t),n=Se.createServer(kt(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 Ae,writeFile as Et}from"node:fs/promises";import{join as ct,resolve as vt,sep as Re}from"node:path";import{matchRoute as Te}from"what-router/match";function ke(t){return t.includes(":")||t.includes("*")||t.includes("[")}function Ee(t,e){return t.replace(/\[\.\.\.(\w+)\]/g,(n,r)=>e[r]??"").replace(/\[(\w+)\]/g,(n,r)=>e[r]??"").replace(/[:*](\w+)/g,(n,r)=>e[r]??"")}function ve(t,e){let n=vt(t),r=vt(ct(t,e==="/"?"":e));if(r!==n&&!r.startsWith(n+Re))throw new Error(`[what-server] Refusing to write outside outDir: ${e}`);return r}async function Ce({routes:t=[],outDir:e,render:n,documentOptions:r={}}={}){let o=[];for(let s of t){let a=s.page&&s.page.mode||s.mode;if(a!=="static"&&a!=="hybrid")continue;let i={default:s.component,loader:s.loader},c=[s.path];if(ke(s.path)){if(typeof s.getStaticPaths!="function")continue;c=((await s.getStaticPaths()).paths||[]).map(d=>Ee(s.path,d.params||{}))}for(let u of c){let d=ve(e,u),l=Te(u,[s]),p={params:l?l.params:{},query:{}},h=n?await n(i,p):await B(i,p,r);if(await Ae(d,{recursive:!0}),await Et(ct(d,"index.html"),h),typeof s.loader=="function"){let y=await s.loader(p);await Et(ct(d,"__what_data.json"),$({loaderData:y}))}o.push(u)}}return{pages:o}}function xe(t={}){return T(t)}async function Oe({outDir:t=".vercel/output",functionName:e="render",runtime:n="nodejs22.x",files:r=null,handler:o="index.mjs",staticDir:s=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 l={version:3,routes:[{handle:"filesystem"},{src:"/.*",dest:`/${e}`}]};await i(u(t,"config.json"),JSON.stringify(l,null,2)),s&&await c(s,u(t,"static"),{recursive:!0});let f=null;if(r&&typeof r=="object"){f=u(t,"functions",`${e}.func`),await a(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,y]of Object.entries(r)){let S=u(f,h);await a(d(S),{recursive:!0}),await i(S,y)}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}}$e(new Pe);export{Dt as action,Oe as buildVercelOutput,I as createActionHandler,oe as createCloudflareHandler,T as createRequestHandler,_e as createServer,xe as createVercelHandler,q as csrfMetaTag,sn as definePage,Ce as exportStatic,Kt as fetchActionHandler,ht as formAction,Q as generateCsrfToken,cn as generateStaticPage,Bt as getRegisteredActions,Ht as getRevalidationHandler,D as handleActionRequest,mt as invalidatePath,Xt as nodeActionMiddleware,Ut as onRevalidate,B as renderDocument,an as renderPage,ce as renderToHydratableString,L as renderToStream,w as renderToString,de as renderToStringAsync,on as renderToStringWithHead,X as revalidatePath,G as revalidateTag,$ as serializeState,un as server,Y as setRevalidationHandler,kt as toNodeListener,yt as useAction,Mt as useFormAction,Jt as useMutation,Ft as useOptimistic,pt as validateCsrfToken,be as whatMiddleware};
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// What Framework Server - TypeScript Definitions
|
|
2
2
|
|
|
3
|
-
import { VNode, VNodeChild, Signal } from '
|
|
3
|
+
import { VNode, VNodeChild, Signal } from 'what-core';
|
|
4
4
|
|
|
5
5
|
// --- SSR ---
|
|
6
6
|
|
|
@@ -10,6 +10,19 @@ export function renderToString(vnode: VNode): string;
|
|
|
10
10
|
/** Render VNode tree as async iterator for streaming */
|
|
11
11
|
export function renderToStream(vnode: VNode): AsyncGenerator<string>;
|
|
12
12
|
|
|
13
|
+
export interface RenderRequestContext {
|
|
14
|
+
params?: Record<string, string>;
|
|
15
|
+
query?: Record<string, string>;
|
|
16
|
+
request?: any;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Run a page module's loader, then render it. Returns the body, head and loader data. */
|
|
21
|
+
export function renderPage(
|
|
22
|
+
pageModule: { default: (props: any) => VNode; loader?: (ctx: RenderRequestContext) => any } | ((props: any) => VNode),
|
|
23
|
+
reqCtx?: RenderRequestContext,
|
|
24
|
+
): Promise<{ body: string; head: string; loaderData: any }>;
|
|
25
|
+
|
|
13
26
|
// --- Page Configuration ---
|
|
14
27
|
|
|
15
28
|
export interface PageConfig {
|
|
@@ -38,6 +51,11 @@ export function generateStaticPage(page: PageConfig, data?: any): string;
|
|
|
38
51
|
export function server<P>(component: (props: P) => VNode): (props: P) => VNode;
|
|
39
52
|
|
|
40
53
|
// --- Islands ---
|
|
54
|
+
//
|
|
55
|
+
// The island runtime (island, Island, hydrateIslands, createIslandStore, …)
|
|
56
|
+
// is exported from the `what-server/islands` subpath, not from this entry.
|
|
57
|
+
// See ./islands.d.ts. The shapes below stay here because they describe values
|
|
58
|
+
// that cross the SSR boundary and are referenced by root-entry consumers.
|
|
41
59
|
|
|
42
60
|
export interface IslandOptions {
|
|
43
61
|
/** Hydration mode */
|
|
@@ -50,40 +68,6 @@ export interface IslandOptions {
|
|
|
50
68
|
stores?: string[];
|
|
51
69
|
}
|
|
52
70
|
|
|
53
|
-
/** Register an island component */
|
|
54
|
-
export function island(
|
|
55
|
-
name: string,
|
|
56
|
-
loader: () => Promise<any>,
|
|
57
|
-
options?: IslandOptions
|
|
58
|
-
): void;
|
|
59
|
-
|
|
60
|
-
/** Island component wrapper for SSR */
|
|
61
|
-
export function Island(props: {
|
|
62
|
-
name: string;
|
|
63
|
-
props?: Record<string, any>;
|
|
64
|
-
mode?: IslandOptions['mode'];
|
|
65
|
-
priority?: number;
|
|
66
|
-
stores?: string[];
|
|
67
|
-
children?: VNodeChild;
|
|
68
|
-
}): VNode;
|
|
69
|
-
|
|
70
|
-
/** Hydrate all islands on the page */
|
|
71
|
-
export function hydrateIslands(): void;
|
|
72
|
-
|
|
73
|
-
/** Auto-discover and register islands */
|
|
74
|
-
export function autoIslands(registry: Record<string, {
|
|
75
|
-
loader: () => Promise<any>;
|
|
76
|
-
mode?: IslandOptions['mode'];
|
|
77
|
-
media?: string;
|
|
78
|
-
priority?: number;
|
|
79
|
-
stores?: string[];
|
|
80
|
-
} | (() => Promise<any>)>): void;
|
|
81
|
-
|
|
82
|
-
/** Boost hydration priority for an island */
|
|
83
|
-
export function boostIslandPriority(name: string, newPriority?: number): void;
|
|
84
|
-
|
|
85
|
-
// --- Shared Island State ---
|
|
86
|
-
|
|
87
71
|
export interface IslandStore<T extends Record<string, any>> {
|
|
88
72
|
_signals: Record<keyof T, Signal<any>>;
|
|
89
73
|
_subscribe: (key: keyof T, fn: (value: any) => void) => () => void;
|
|
@@ -92,34 +76,6 @@ export interface IslandStore<T extends Record<string, any>> {
|
|
|
92
76
|
_hydrate: (data: Partial<T>) => void;
|
|
93
77
|
}
|
|
94
78
|
|
|
95
|
-
/** Create a shared store for islands */
|
|
96
|
-
export function createIslandStore<T extends Record<string, any>>(
|
|
97
|
-
name: string,
|
|
98
|
-
initialState: T
|
|
99
|
-
): T & IslandStore<T>;
|
|
100
|
-
|
|
101
|
-
/** Get or create a shared store */
|
|
102
|
-
export function useIslandStore<T extends Record<string, any>>(
|
|
103
|
-
name: string,
|
|
104
|
-
fallbackInitial?: T
|
|
105
|
-
): T & IslandStore<T>;
|
|
106
|
-
|
|
107
|
-
/** Serialize all shared stores for SSR */
|
|
108
|
-
export function serializeIslandStores(): string;
|
|
109
|
-
|
|
110
|
-
/** Hydrate shared stores from SSR data */
|
|
111
|
-
export function hydrateIslandStores(serialized: string | Record<string, any>): void;
|
|
112
|
-
|
|
113
|
-
// --- Progressive Enhancement ---
|
|
114
|
-
|
|
115
|
-
/** Enhance elements matching selector */
|
|
116
|
-
export function enhance(selector: string, handler: (el: Element) => void): void;
|
|
117
|
-
|
|
118
|
-
/** Enhance forms for AJAX submission */
|
|
119
|
-
export function enhanceForms(selector?: string): void;
|
|
120
|
-
|
|
121
|
-
// --- Debugging ---
|
|
122
|
-
|
|
123
79
|
export interface IslandStatus {
|
|
124
80
|
registered: string[];
|
|
125
81
|
hydrated: number;
|
|
@@ -128,8 +84,6 @@ export interface IslandStatus {
|
|
|
128
84
|
stores: string[];
|
|
129
85
|
}
|
|
130
86
|
|
|
131
|
-
export function getIslandStatus(): IslandStatus;
|
|
132
|
-
|
|
133
87
|
// --- Server Actions ---
|
|
134
88
|
|
|
135
89
|
export interface ActionOptions {
|
package/islands.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// What Framework Server Islands - TypeScript Definitions
|
|
2
|
+
|
|
3
|
+
import { VNode, VNodeChild, Signal } from 'what-core';
|
|
4
|
+
|
|
5
|
+
// --- Islands ---
|
|
6
|
+
|
|
7
|
+
export interface IslandOptions {
|
|
8
|
+
/** Hydration mode */
|
|
9
|
+
mode?: 'static' | 'idle' | 'visible' | 'load' | 'media' | 'action';
|
|
10
|
+
/** Media query for 'media' mode */
|
|
11
|
+
media?: string;
|
|
12
|
+
/** Priority (higher = hydrate first) */
|
|
13
|
+
priority?: number;
|
|
14
|
+
/** Shared stores this island uses */
|
|
15
|
+
stores?: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Register an island component */
|
|
19
|
+
export function island(
|
|
20
|
+
name: string,
|
|
21
|
+
loader: () => Promise<any>,
|
|
22
|
+
options?: IslandOptions
|
|
23
|
+
): void;
|
|
24
|
+
|
|
25
|
+
/** Island component wrapper for SSR */
|
|
26
|
+
export function Island(props: {
|
|
27
|
+
name: string;
|
|
28
|
+
props?: Record<string, any>;
|
|
29
|
+
mode?: IslandOptions['mode'];
|
|
30
|
+
priority?: number;
|
|
31
|
+
stores?: string[];
|
|
32
|
+
children?: VNodeChild;
|
|
33
|
+
}): VNode;
|
|
34
|
+
|
|
35
|
+
/** Hydrate all islands on the page */
|
|
36
|
+
export function hydrateIslands(): void;
|
|
37
|
+
|
|
38
|
+
/** Auto-discover and register islands */
|
|
39
|
+
export function autoIslands(registry: Record<string, {
|
|
40
|
+
loader: () => Promise<any>;
|
|
41
|
+
mode?: IslandOptions['mode'];
|
|
42
|
+
media?: string;
|
|
43
|
+
priority?: number;
|
|
44
|
+
stores?: string[];
|
|
45
|
+
} | (() => Promise<any>)>): void;
|
|
46
|
+
|
|
47
|
+
/** Boost hydration priority for an island */
|
|
48
|
+
export function boostIslandPriority(name: string, newPriority?: number): void;
|
|
49
|
+
|
|
50
|
+
// --- Shared Island State ---
|
|
51
|
+
|
|
52
|
+
export interface IslandStore<T extends Record<string, any>> {
|
|
53
|
+
_signals: Record<keyof T, Signal<any>>;
|
|
54
|
+
_subscribe: (key: keyof T, fn: (value: any) => void) => () => void;
|
|
55
|
+
_batch: (fn: () => void) => void;
|
|
56
|
+
_getSnapshot: () => T;
|
|
57
|
+
_hydrate: (data: Partial<T>) => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Create a shared store for islands */
|
|
61
|
+
export function createIslandStore<T extends Record<string, any>>(
|
|
62
|
+
name: string,
|
|
63
|
+
initialState: T
|
|
64
|
+
): T & IslandStore<T>;
|
|
65
|
+
|
|
66
|
+
/** Get or create a shared store */
|
|
67
|
+
export function useIslandStore<T extends Record<string, any>>(
|
|
68
|
+
name: string,
|
|
69
|
+
fallbackInitial?: T
|
|
70
|
+
): T & IslandStore<T>;
|
|
71
|
+
|
|
72
|
+
/** Serialize all shared stores for SSR */
|
|
73
|
+
export function serializeIslandStores(): string;
|
|
74
|
+
|
|
75
|
+
/** Snapshot every shared store for the current render context */
|
|
76
|
+
export function getIslandStoresSnapshot(context?: any): Record<string, any>;
|
|
77
|
+
|
|
78
|
+
/** Hydrate shared stores from SSR data */
|
|
79
|
+
export function hydrateIslandStores(serialized: string | Record<string, any>): void;
|
|
80
|
+
|
|
81
|
+
// --- Progressive Enhancement ---
|
|
82
|
+
|
|
83
|
+
/** Enhance elements matching selector */
|
|
84
|
+
export function enhance(selector: string, handler: (el: Element) => void): void;
|
|
85
|
+
|
|
86
|
+
/** Enhance forms for AJAX submission */
|
|
87
|
+
export function enhanceForms(selector?: string): void;
|
|
88
|
+
|
|
89
|
+
// --- Debugging ---
|
|
90
|
+
|
|
91
|
+
export interface IslandStatus {
|
|
92
|
+
registered: string[];
|
|
93
|
+
hydrated: number;
|
|
94
|
+
pending: number;
|
|
95
|
+
queue: { name: string; priority: number }[];
|
|
96
|
+
stores: string[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function getIslandStatus(): IslandStatus;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "what-server",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.8",
|
|
4
4
|
"description": "What Framework - SSR, islands architecture, static generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -8,11 +8,17 @@
|
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./index.d.ts",
|
|
11
|
+
"node": {
|
|
12
|
+
"production": "./dist/node.min.js",
|
|
13
|
+
"import": "./src/node.js",
|
|
14
|
+
"default": "./src/node.js"
|
|
15
|
+
},
|
|
11
16
|
"production": "./dist/index.min.js",
|
|
12
17
|
"import": "./src/index.js",
|
|
13
18
|
"default": "./src/index.js"
|
|
14
19
|
},
|
|
15
20
|
"./islands": {
|
|
21
|
+
"types": "./islands.d.ts",
|
|
16
22
|
"production": "./dist/islands.min.js",
|
|
17
23
|
"import": "./src/islands.js",
|
|
18
24
|
"default": "./src/islands.js"
|
|
@@ -26,9 +32,13 @@
|
|
|
26
32
|
"files": [
|
|
27
33
|
"src",
|
|
28
34
|
"dist/**/*.min.js",
|
|
29
|
-
"index.d.ts"
|
|
35
|
+
"index.d.ts",
|
|
36
|
+
"islands.d.ts"
|
|
37
|
+
],
|
|
38
|
+
"sideEffects": [
|
|
39
|
+
"./src/node.js",
|
|
40
|
+
"./dist/node.min.js"
|
|
30
41
|
],
|
|
31
|
-
"sideEffects": false,
|
|
32
42
|
"keywords": [
|
|
33
43
|
"ssr",
|
|
34
44
|
"islands",
|
|
@@ -39,8 +49,8 @@
|
|
|
39
49
|
"author": "ZVN DEV (https://zvndev.com)",
|
|
40
50
|
"license": "MIT",
|
|
41
51
|
"peerDependencies": {
|
|
42
|
-
"what-core": "^0.11.
|
|
43
|
-
"what-router": "^0.11.
|
|
52
|
+
"what-core": "^0.11.8",
|
|
53
|
+
"what-router": "^0.11.8"
|
|
44
54
|
},
|
|
45
55
|
"peerDependenciesMeta": {
|
|
46
56
|
"what-router": {
|