what-server 0.12.1 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +7 -7
- package/dist/islands.min.js +2 -1
- package/dist/node.min.js +7 -7
- package/node.d.ts +12 -1
- package/package.json +4 -4
- package/src/index.js +67 -4
- package/src/islands.js +161 -35
package/dist/index.min.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{h as wt,_isAriaAttr as ne,getServerContext as St,runWithServerContext as S,beginHeadCollection as re,endHeadCollection as tt}from"what-core";var At=new RegExp("[<>&\\u2028\\u2029]","g"),Tt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function J(t){return JSON.stringify(t).replace(At,e=>Tt[e.charCodeAt(0)])}import{mount as Se,hydrate as be,signal as _e,batch as Ae,getServerContext as kt}from"what-core";var Rt=new Map;function Et(t){let e=t||kt();return e&&e.islandStores instanceof Map?e.islandStores:null}function it(t){let e=typeof document<"u"?Rt:Et(t),n={};for(let[r,o]of e||[])n[r]=o._getSnapshot();return n}import{signal as _,batch as X}from"what-core";var T=null,ct=!(typeof process<"u");function W(t){T=t}function Ct(){return T}async function V(t,e){if(T&&T.revalidatePath)return T.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 z(t,e){if(T&&T.revalidateTag)return T.revalidateTag(t,e);ct&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var Y=new Map;function vt(){if(typeof document<"u"){let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);if(e)return decodeURIComponent(e[1])}return null}function K(){if(typeof crypto<"u"&&crypto.randomUUID)return crypto.randomUUID();if(typeof crypto<"u"&&crypto.getRandomValues){let t=new Uint8Array(16);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}throw new Error("[what] No secure random source available for CSRF token generation")}function dt(t,e){if(!t||!e||t.length!==e.length)return!1;let n=0;for(let r=0;r<t.length;r++)n|=t.charCodeAt(r)^e.charCodeAt(r);return n===0}function Z(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}var Ot=0,xt=!1;function Pt(){return!xt&&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${(++Ot).toString(36)}_${Date.now().toString(36)}`}`}function $t(t,e={}){let n=e.id||Pt(),{onError:r,onSuccess:o,revalidate:s}=e;typeof window>"u"&&Y.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=vt(),l={"Content-Type":"application/json","X-What-Action":n};f&&(l["X-CSRF-Token"]=f);let p=await fetch("/__what_action",{method:"POST",headers:l,credentials:"same-origin",signal: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)lt(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 ut(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 ft(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 It(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},o=ft(ut(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 Ht(t,e){let n=_(t),r=_([]),o=_(t);function s(d){let u=e(n.peek(),d);X(()=>{r.set([...r.peek(),d]),n.set(u)})}function a(d,u){X(()=>{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){X(()=>{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 Nt(t,e){return P.has(t)||P.set(t,new Set),P.get(t).add(e),()=>{P.get(t)?.delete(e)}}function lt(t){let e=P.get(t);if(e)for(let n of e)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function N(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(!dt(i,o))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let a=Y.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 V(d);if(Array.isArray(c.revalidateTags))for(let d of c.revalidateTags)await z(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 Dt(){return[...Y.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)}}}import{h as D}from"what-core";var pt="/__what_action";function Lt(t){if(typeof t=="string")return t;if(typeof t=="function"){let e=t._actionId;if(e)return e;throw new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string.")}throw new Error("[what] <Form> requires an `action` prop: a server action or its id.")}function Mt(){if(typeof document>"u")return null;let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return e?decodeURIComponent(e[1]):null}function Ft({action:t,csrfToken:e,redirect:n,method:r="post",enhance:o=!0,children:s,...a}){let i=Lt(t),c=e!==void 0?e:Mt();c==null&&typeof process<"u";let d=[D("input",{type:"hidden",name:"_action",value:i}),D("input",{type:"hidden",name:"what-csrf-token",value:c||""})];n&&d.push(D("input",{type:"hidden",name:"_redirect",value:n}));let u={...a,method:r,action:a.action||pt,"data-action":i};o&&(u["data-enhance"]="");let f=s==null?[]:Array.isArray(s)?s:[s];return D("form",u,...d,...f)}var Ut="/__what_action",yt=1024*1024;function Bt(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 G(t,e){return{status:t,headers:{"content-type":"text/html; charset=utf-8"},body:`<!DOCTYPE html><html><body><h1>${t}</h1><p>${String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</p></body></html>`}}function ht(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 Jt(t,e){let n=ht(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let o=new URL(r,"http://localhost"),s=ht(o.pathname+o.search);if(s)return s}catch{}return"/"}var Wt=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=Bt(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 G(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 G(403,"Missing CSRF token");let C={};for(let[v,U]of Object.entries(h))Wt.has(v)||(C[v]=U);let R=await N({headers:b},g,[C],{csrfToken:u,skipCsrf:n});return R.status===200?{status:303,headers:{location:Jt(h,a)},body:""}:G(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 N({headers:a},i,l,{csrfToken:u,skipCsrf:n});return j(p.status,p.body)}}function Vt(t={}){let e=t.basePath||Ut,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 zt(o);d=L(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 L(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 M(t,e=yt){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 zt(t){return new Promise((e,n)=>{let r=0,o=[];t.on("data",s=>{if(r+=s.length,r>yt){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 Xt(t={}){let e=$(t);return async function(n){let r={};try{let a=await M(n);if(a.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=L(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 Yt,parseQuery as Kt}from"what-router/match";var Zt="/__what_action",Gt="/__what_revalidate",Q="what-csrf";function I(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 Qt(t){try{let e=await M(t);return e.tooLarge?{tooLarge:!0}:L(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function qt(t){let e;try{e=await M(t)}catch{return{json:{}}}if(e.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(e.raw)}}catch{return{json:{}}}}function te(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 gt(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=>mt(l.headers&&l.headers.cookie,Q)}:{skipCsrf:!0}),f=r||te(s);return n&&(n.revalidatePath||n.revalidateTag)&&W({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===Zt){let y=await Qt(p);if(y&&y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await u({method:"POST",headers:I(p.headers),body:y,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let b=null,E=null;if(d&&(b=mt(I(p.headers).cookie,Q),!b)){b=K();let A=I(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;E=`${Q}=${encodeURIComponent(b)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let C=y=>(E&&(y["set-cookie"]=E),y);if(p.method==="POST"&&g===Gt&&o){let y=await qt(p);if(y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await o({headers:I(p.headers),body:y.json});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let R=Yt(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:U}=R,B=v.page||{mode:v.mode||"client"},x={path:g,query:Kt(h.search),config:B,route:v,params:U,request:p};if(n&&B.mode!=="server"){x.varyHeaders=I(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 at=await f(x),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})}}function ee(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:re(),loaderData:t,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var bt=0;function oe(){bt=0}function ae(){return"h"+bt++}function se(t){if(!St()){let e=k(void 0);return S(e,()=>se(t))}return oe(),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=ae(),d=t.tag({...t.props,children:t.children}),u=O(d);return ie(u,c)}let{tag:e,props:n,children:r}=t;nt(e);let o=rt(n||{}),s=`<${e}${o}>`;if(ot.has(e))return s;let a=et(n),i=a!=null?String(a):r.map(O).join("");return`${s}${i}</${e}>`}function ie(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(!St()){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;nt(e);let o=rt(n||{}),s=`<${e}${o}>`;if(ot.has(e))return s;let a=et(n),i=a!=null?String(a):r.map(w).join("");return`${s}${i}</${e}>`}function We(t){let e=k(void 0);return{body:S(e,()=>w(t)),head:tt(e.head)}}async function Ve(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(wt(n,{...s,loaderData:r}))),head:tt(o.head),loaderData:r}}var _t=12;async function ce(t,e){e||(e=k(void 0));let n="";for(let o=0;o<_t;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:tt(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function gt(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 ce(wt(r,{...a,loaderData:o}),s),u={loaderData:o??null,resources:d,islandStores:it(s)};return de({body:i,head:c,payload:u,options:n})}function de({body:t,head:e,payload:n,options:r={}}){let o=r.lang||"en",s=`<script id="__what_data" type="application/json">${J(n)}<\/script>`,a=r.clientEntry?`<script type="module" src="${m(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?Z(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*H(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*H(a,e);return}if(typeof t=="function"){try{let a=S(e,()=>t());yield*H(a,e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let a of t)yield*H(a,e);return}if(t.tag==="__suspense"){let a=null;for(let i=0;i<_t&&a===null;i++){let c=null;try{a=S(e,()=>(t.children||[]).map(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*H(i,e)}catch(a){typeof process<"u",yield F?`<!-- SSR Error: ${m(a.message||"Component error")} -->`:"<!-- SSR Error -->"}return}let{tag:n,props:r,children:o}=t;nt(n);let s=rt(r||{});if(yield`<${n}${s}>`,!ot.has(n)){let a=et(r);if(a!=null)yield String(a);else for(let i of o)yield*H(i,e);yield`</${n}>`}}function ze(t){return{mode:"static",...t}}function Xe(t,e={}){let n=k(e),r=S(n,()=>{let s=t.component(e);return w(s)}),o=t.islands||[];return ue({title:t.title||"",meta:t.meta||{},body:r,islands:o,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function ue({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="${
|
|
3
|
-
`),
|
|
1
|
+
import{h as _e,_isAriaAttr as at,_beginComponentSSR as ee,_endComponentSSR as te,_mapArrayToArray as ne,getServerContext as Ae,runWithServerContext as S,beginHeadCollection as st,endHeadCollection as re}from"what-core";var Ee=new RegExp("[<>&\\u2028\\u2029]","g"),Re={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function J(e){return JSON.stringify(e).replace(Ee,t=>Re[t.charCodeAt(0)])}import{mount as At,hydrate as kt,signal as Tt,batch as Et,getServerContext as Ce}from"what-core";var ve=new Map;function Oe(e){let t=e||Ce();return t&&t.islandStores instanceof Map?t.islandStores:null}function de(e){let t=typeof document<"u"?ve:Oe(e),n={};for(let[r,o]of t||[])n[r]=o._getSnapshot();return n}import{signal as _,batch as X}from"what-core";var k=null,fe=!(typeof process<"u");function V(e){k=e}function $e(){return k}async function W(e,t){if(k&&k.revalidatePath)return k.revalidatePath(e,t);fe&&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 z(e,t){if(k&&k.revalidateTag)return k.revalidateTag(e,t);fe&&console.warn(`[what] revalidateTag('${e}') had no effect: no cache engine is bound.`)}var Y=new Map;function xe(){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 K(){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 le(e,t){if(!e||!t||e.length!==t.length)return!1;let n=0;for(let r=0;r<e.length;r++)n|=e.charCodeAt(r)^t.charCodeAt(r);return n===0}function Z(e){return`<meta name="what-csrf-token" content="${String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}var Pe=0,Ie=!1;function Ne(){return!Ie&&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${(++Pe).toString(36)}_${Date.now().toString(36)}`}`}function He(e,t={}){let n=t.id||Ne(),{onError:r,onSuccess:o,revalidate:s}=t;typeof window>"u"&&Y.set(n,{fn:e,options:t});async function a(...i){if(typeof window>"u")return e(...i);let c=t.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let f=xe(),l={"Content-Type":"application/json","X-What-Action":n};f&&(l["X-CSRF-Token"]=f);let p=await fetch("/__what_action",{method:"POST",headers:l,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let w=await p.json().catch(()=>({message:"Action failed"}));throw new Error(w.message||"Action failed")}let h=await p.json();if(o&&o(h),s)for(let w of s)ye(w);return h}catch(f){if(f.name==="AbortError"){let l=new Error(`Action "${n}" timed out after ${c}ms`);throw l.code="TIMEOUT",r&&r(l),l}throw r&&r(f),f}finally{clearTimeout(d)}}return a._actionId=n,a._isAction=!0,a}function pe(e,t={}){let{onSuccess:n,onError:r,resetOnSuccess:o=!0}=t;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,f]of a.entries())typeof File<"u"&&f instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(f):c[d]=[c[d],f]:c[d]=f;try{let d=u?await e(c,a):await e(c);return n&&n(d,i),o&&i&&i.reset(),d}catch(d){throw r&&r(d,i),d}}}function he(e){let t=_(!1),n=_(null),r=_(null);async function o(...s){t.set(!0),n.set(null);try{let a=await e(...s);return r.set(a),a}catch(a){throw n.set(a),a}finally{t.set(!1)}}return{trigger:o,isPending:()=>t(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Le(e,t={}){let{resetOnSuccess:n=!0}=t,r={current:null},o=he(pe(e,{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 De(e,t){let n=_(e),r=_([]),o=_(e);function s(u){let d=t(n.peek(),u);X(()=>{r.set([...r.peek(),u]),n.set(d)})}function a(u,d){X(()=>{if(r.set(r.peek().filter(f=>f!==u)),d!==void 0){o.set(d);let f=d;for(let l of r.peek())f=t(f,l);n.set(f)}})}function i(u,d){X(()=>{let f=r.peek().filter(h=>h!==u);r.set(f);let l=d!==void 0?d:o.peek();o.set(l);let p=l;for(let h of f)p=t(p,h);n.set(p)})}async function c(u,d){s(u);try{let f=await d();return a(u,f),f}catch(f){throw i(u),f}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:s,resolve:a,rollback:i,withOptimistic:c,set:u=>{n.set(u),o.set(u)}}}var P=new Map;function je(e,t){return P.has(e)||P.set(e,new Set),P.get(e).add(t),()=>{P.get(e)?.delete(t)}}function ye(e){let t=P.get(e);if(t)for(let n of t)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function H(e,t,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=e?.headers?.["x-csrf-token"]||e?.headers?.["X-CSRF-Token"];if(!le(i,o))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let a=Y.get(t);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 W(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await z(u);return{status:200,body:i}}).catch(i=>(console.error(`[what] Action "${t}" error:`,i),{status:500,body:{message:"Action failed"}})):Promise.resolve({status:400,body:{message:"Invalid action arguments"}}):Promise.resolve({status:404,body:{message:"Action not found"}})}function Me(){return[...Y.keys()]}function Fe(e,t={}){let{onSuccess:n,onError:r,onSettled:o}=t,s={isPending:_(!1),error:_(null),data:_(null)};async function a(...i){s.isPending.set(!0),s.error.set(null);try{let c=await e(...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)}}}import{h as L}from"what-core";var me="/__what_action";function Ue(e){if(typeof e=="string")return e;if(typeof e=="function"){let t=e._actionId;if(t)return t;throw new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string.")}throw new Error("[what] <Form> requires an `action` prop: a server action or its id.")}function Be(){if(typeof document>"u")return null;let e=document.querySelector('meta[name="what-csrf-token"]');if(e)return e.getAttribute("content");let t=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return t?decodeURIComponent(t[1]):null}function Je({action:e,csrfToken:t,redirect:n,method:r="post",enhance:o=!0,children:s,...a}){let i=Ue(e),c=t!==void 0?t:Be();c==null&&typeof process<"u";let u=[L("input",{type:"hidden",name:"_action",value:i}),L("input",{type:"hidden",name:"what-csrf-token",value:c||""})];n&&u.push(L("input",{type:"hidden",name:"_redirect",value:n}));let d={...a,method:r,action:a.action||me,"data-action":i};o&&(d["data-enhance"]="");let f=s==null?[]:Array.isArray(s)?s:[s];return L("form",d,...u,...f)}var Ve="/__what_action",we=1024*1024;function We(e){if(!e)return{};if(typeof e.forEach=="function"&&typeof e.get=="function"){let n={};return e.forEach((r,o)=>{n[o.toLowerCase()]=r}),n}let t={};for(let n in e)t[n.toLowerCase()]=e[n];return t}function D(e,t){return{status:e,headers:{"content-type":"application/json"},body:JSON.stringify(t)}}function G(e,t){return{status:e,headers:{"content-type":"text/html; charset=utf-8"},body:`<!DOCTYPE html><html><body><h1>${e}</h1><p>${String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</p></body></html>`}}function ge(e){if(typeof e!="string"||!e.startsWith("/")||/^[/\\]{2}/.test(e)||e.includes("\\"))return null;try{let t=new URL(e,"http://localhost");return t.origin!=="http://localhost"?null:t.pathname+t.search}catch{return null}}function ze(e,t){let n=ge(e&&e._redirect);if(n)return n;let r=t.referer||t.referrer;if(r)try{let o=new URL(r,"http://localhost"),s=ge(o.pathname+o.search);if(s)return s}catch{}return"/"}var Xe=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function I(e={}){let{getCsrfToken:t,skipCsrf:n=!1}=e;return async function(o){if((o.method||"POST").toUpperCase()!=="POST")return D(405,{message:"Method Not Allowed"});let a=We(o.headers),i=a["x-what-action"],c=a["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=n?void 0:t?await t(o):void 0;if(u){let h=o.body||{},w=h._action||h["data-action"]||o.query&&o.query.action;if(!w)return G(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let b={...a},C=h._csrf??h["what-csrf-token"];if(C&&!b["x-csrf-token"]&&(b["x-csrf-token"]=String(C)),!n&&t&&!d)return G(403,"Missing CSRF token");let v={};for(let[O,U]of Object.entries(h))Xe.has(O)||(v[O]=U);let E=await H({headers:b},w,[v],{csrfToken:d,skipCsrf:n});return E.status===200?{status:303,headers:{location:ze(h,a)},body:""}:G(E.status,E.body&&E.body.message||"Action failed")}if(!i)return D(400,{message:"Missing X-What-Action header"});if(!n&&t&&!d)return D(403,{message:"Missing CSRF token"});let l=(o.body||{}).args,p=await H({headers:a},i,l,{csrfToken:d,skipCsrf:n});return D(p.status,p.body)}}function Ye(e={}){let t=e.basePath||Ve,n=I(e);return async function(o,s,a){let[i,c]=(o.url||"").split("?");if(i!==t||(o.method||"").toUpperCase()!=="POST")return a?a():void 0;let u;try{let l=await Ke(o);u=j(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 d=Object.fromEntries(new URLSearchParams(c||"")),f=await n({method:o.method,headers:o.headers,body:u,query:d});s.writeHead(f.status,f.headers),s.end(f.body)}}function j(e,t){if((t||"").includes("application/x-www-form-urlencoded")){let n={};for(let[r,o]of new URLSearchParams(String(e)))n[r]===void 0?n[r]=o:Array.isArray(n[r])?n[r].push(o):n[r]=[n[r],o];return n}return e==null||e===""?{}:JSON.parse(String(e))}async function M(e,t=we){let n=Number(e.headers.get("content-length"));if(Number.isFinite(n)&&n>t)return{tooLarge:!0};let r=e.body;if(!r||typeof r.getReader!="function"){let i=await e.text();return Buffer.byteLength(i,"utf8")>t?{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>t){try{await o.cancel()}catch{}return{tooLarge:!0}}s.push(c)}}return{raw:Buffer.concat(s.map(i=>Buffer.from(i))).toString("utf8")}}function Ke(e){return new Promise((t,n)=>{let r=0,o=[];e.on("data",s=>{if(r+=s.length,r>we){let a=new Error("Body too large");a.code="BODY_TOO_LARGE",n(a),e.destroy?.();return}o.push(s)}),e.on("end",()=>{if(o.length===0)return t("");t(Buffer.concat(o).toString("utf8"))}),e.on("error",n)})}function Ze(e={}){let t=I(e);return async function(n){let r={};try{let a=await M(n);if(a.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=j(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 t({method:n.method,headers:n.headers,body:r,query:o});return new Response(s.body,{status:s.status,headers:s.headers})}}import{matchRoute as Ge,parseQuery as Qe}from"what-router/match";var qe="/__what_action",et="/__what_revalidate",Q="what-csrf";function N(e){let t={};return e&&typeof e.forEach=="function"&&e.forEach((n,r)=>{t[r.toLowerCase()]=n}),t}function Se(e,t){if(!e)return null;let n=String(e).match(new RegExp(`(?:^|;\\s*)${t}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function tt(e){try{let t=await M(e);return t.tooLarge?{tooLarge:!0}:j(t.raw,e.headers.get("content-type")||"")}catch{return{}}}async function nt(e){let t;try{t=await M(e)}catch{return{json:{}}}if(t.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(t.raw)}}catch{return{json:{}}}}function rt(e){return async function(n){let{route:r,params:o,query:s,request:a}=n,i={default:r.component,loader:r.loader},c=n.csrfToken?{...e,csrfToken:n.csrfToken}:e;return{html:await be(i,{params:o,query:s,request:a},c),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function q(e={}){let{routes:t=[],cache:n,render:r,revalidateWebhook:o,document:s={},notFound:a,basePath:i="",csrf:c=!0}=e,u=c!==!1&&!e.actionHandler,d=e.actionHandler||I(u?{getCsrfToken:l=>Se(l.headers&&l.headers.cookie,Q)}:{skipCsrf:!0}),f=r||rt(s);return n&&(n.revalidatePath||n.revalidateTag)&&V({revalidatePath:n.revalidatePath,revalidateTag:n.revalidateTag}),async function(p){let h=new URL(p.url,"http://localhost"),w=h.pathname;if(i&&w.startsWith(i)&&(w=w.slice(i.length)||"/"),p.method==="POST"&&w===qe){let y=await tt(p);if(y&&y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await d({method:"POST",headers:N(p.headers),body:y,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let b=null,C=null;if(u&&(b=Se(N(p.headers).cookie,Q),!b)){b=K();let A=N(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;C=`${Q}=${encodeURIComponent(b)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let v=y=>(C&&(y["set-cookie"]=C),y);if(p.method==="POST"&&w===et&&o){let y=await nt(p);if(y.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:y.json});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let E=Ge(w,t);if(!E){let y=a?a():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(y,{status:404,headers:v({"content-type":"text/html; charset=utf-8"})})}let{route:O,params:U}=E,B=O.page||{mode:O.mode||"client"},x={path:w,query:Qe(h.search),config:B,route:O,params:U,request:p};if(n&&B.mode!=="server"){x.varyHeaders=N(p.headers);let y=await n.handle(x,()=>f(x));return new Response(y.html,{status:y.status||200,headers:v({"content-type":"text/html; charset=utf-8",...y.headers||{}})})}b&&(x.csrfToken=b);let ce=await f(x),ue=v({"content-type":"text/html; charset=utf-8"});return B.mode==="server"&&(ue["Cache-Control"]="private, no-store"),new Response(ce.html,{status:ce.status||200,headers:ue})}}function ot(e={}){let t=q(e);return{async fetch(n,r,o){return r&&(n.__env=r),o&&(n.__ctx=o),t(n)}}}function T(e){return{head:st(),loaderData:e,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var ke=0;function it(){ke=0}function ct(){return"h"+ke++}function ut(e){if(!Ae()){let t=T(void 0);return S(t,()=>ut(e))}return it(),R(e)}function R(e){if(e==null||e===!1||e===!0)return"";if(typeof e=="string"||typeof e=="number")return g(String(e));if(typeof e=="function"&&e._signal)return`<!--$-->${R(e())}<!--/$-->`;if(typeof e=="function"&&e._mapArray)try{return`<!--$-->${R(ne(e))}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(typeof e=="function")try{return`<!--$-->${R(e())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(e))return`<!--[]-->${e.map(R).join("")}<!--/[]-->`;if(typeof e.tag=="function"){let c=ct(),u=ee(e.tag),d;try{d=R(e.tag({...e.props,children:e.children}))}finally{te(u)}return dt(d,c)}let{tag:t,props:n,children:r}=e;ae(t);let o=se(n||{}),s=`<${t}${o}>`;if(ie.has(t))return s;let a=oe(n),i=a!=null?String(a):r.map(R).join("");return`${s}${i}</${t}>`}function dt(e,t){let n=e.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],o=n[2],s=r.length+1+o.length;return e.slice(0,s)+` data-hk="${t}"`+e.slice(s)}return e}function m(e){if(!Ae()){let c=T(void 0);return S(c,()=>m(e))}if(e==null||e===!1||e===!0)return"";if(typeof e=="string"||typeof e=="number")return g(String(e));if(typeof e=="function"&&e._signal)return m(e());if(typeof e=="function"&&e._mapArray)try{return m(ne(e))}catch{return typeof process<"u",""}if(typeof e=="function")try{return m(e())}catch{return typeof process<"u",""}if(Array.isArray(e))return e.map(m).join("");if(e.tag==="__suspense")try{return(e.children||[]).map(m).join("")}catch(c){if(c&&typeof c.then=="function")return m(e.props&&e.props.fallback);throw c}if(typeof e.tag=="function"){let c=ee(e.tag);try{return m(e.tag({...e.props,children:e.children}))}finally{te(c)}}let{tag:t,props:n,children:r}=e;ae(t);let o=se(n||{}),s=`<${t}${o}>`;if(ie.has(t))return s;let a=oe(n),i=a!=null?String(a):r.map(m).join("");return`${s}${i}</${t}>`}function Xt(e){let t=T(void 0);return{body:S(t,()=>m(e)),head:re(t.head)}}async function Yt(e,t={}){let n=e.default||e,r=typeof e.loader=="function"?await e.loader(t):void 0,o=T(r),s=t.params||{};return{body:S(o,()=>m(_e(n,{...s,loaderData:r}))),head:re(o.head),loaderData:r}}var Te=12;async function ft(e,t){t||(t=T(void 0));let n="";for(let o=0;o<Te;o++){n=S(t,()=>m(e));let s=[...t.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 t.resources)s.status==="ready"&&(r[o]=s.value);return{body:n,head:re(t.head),loaderData:t.loaderData,resources:r,ctx:t}}async function be(e,t={},n={}){let r=e.default||e,o=typeof e.loader=="function"?await e.loader(t):void 0,s=T(o),a=t.params||{},{body:i,head:c,resources:u}=await ft(_e(r,{...a,loaderData:o}),s),d={loaderData:o??null,resources:u,islandStores:de(s)};return lt({body:i,head:c,payload:d,options:n})}function lt({body:e,head:t,payload:n,options:r={}}){let o=r.lang||"en",s=`<script id="__what_data" type="application/json">${J(n)}<\/script>`,a=r.clientEntry?`<script type="module" src="${g(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?Z(r.csrfToken):"")+(r.head||""),u=r.bodyClass?` class="${g(r.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${g(o)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${t||""}${c}</head><body${u}>${e}${s}${a}</body></html>`}async function*$(e,t){if(t===void 0&&(t=T(void 0)),e==null||e===!1||e===!0)return;if(typeof e=="string"||typeof e=="number"){yield g(String(e));return}if(typeof e=="function"&&e._signal){let a=S(t,()=>e());yield*$(a,t);return}if(typeof e=="function"&&e._mapArray){let a=null;try{a=S(t,()=>ne(e))}catch{typeof process<"u"}a&&(yield*$(a,t));return}if(typeof e=="function"){try{let a=S(t,()=>e());yield*$(a,t)}catch{typeof process<"u"}return}if(Array.isArray(e)){for(let a of e)yield*$(a,t);return}if(e.tag==="__suspense"){let a=null;for(let i=0;i<Te&&a===null;i++){let c=null;try{a=S(t,()=>(e.children||[]).map(m).join(""))}catch(u){if(u&&typeof u.then=="function")c=u;else throw u}if(a===null){let u=[...t.resources.values()].filter(d=>d.status==="pending").map(d=>d.promise);await Promise.all([c,...u].filter(Boolean))}}a===null&&(a=S(t,()=>m(e.props&&e.props.fallback))),yield a;return}if(typeof e.tag=="function"){let a=ee(e.tag);try{let i=S(t,()=>e.tag({...e.props,children:e.children})),c=i instanceof Promise?await i:i;yield*$(c,t)}catch(i){typeof process<"u",yield F?`<!-- SSR Error: ${g(i.message||"Component error")} -->`:"<!-- SSR Error -->"}finally{te(a)}return}let{tag:n,props:r,children:o}=e;ae(n);let s=se(r||{});if(yield`<${n}${s}>`,!ie.has(n)){let a=oe(r);if(a!=null)yield String(a);else for(let i of o)yield*$(i,t);yield`</${n}>`}}function Kt(e){return{mode:"static",...e}}function Zt(e,t={}){let n=T(t),r=S(n,()=>{let s=e.component(t);return m(s)}),o=e.islands||[];return pt({title:e.title||"",meta:e.meta||{},body:r,islands:o,scripts:e.mode==="static"?[]:e.scripts||[],styles:e.styles||[],mode:e.mode})}function pt({title:e,meta:t,body:n,islands:r,scripts:o,styles:s,mode:a}){let i=Object.entries(t).map(([l,p])=>`<meta name="${g(l)}" content="${g(p)}">`).join(`
|
|
2
|
+
`),c=s.map(l=>`<link rel="stylesheet" href="${g(l)}">`).join(`
|
|
3
|
+
`),u=r.length>0?`
|
|
4
4
|
<script type="module">
|
|
5
5
|
import { hydrateIslands } from '/@what/islands.js';
|
|
6
6
|
hydrateIslands();
|
|
7
|
-
<\/script>`:"",
|
|
7
|
+
<\/script>`:"",d=o.map(l=>`<script type="module" src="${g(l)}"><\/script>`).join(`
|
|
8
8
|
`),f=a==="client"?`
|
|
9
9
|
<script type="module" src="/@what/client.js"><\/script>`:"";return`<!DOCTYPE html>
|
|
10
10
|
<html lang="en">
|
|
@@ -12,13 +12,13 @@ import{h as wt,_isAriaAttr as ne,getServerContext as St,runWithServerContext as
|
|
|
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>${g(e)}</title>
|
|
16
16
|
${c}
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="app">${n}</div>
|
|
20
|
-
${d}
|
|
21
20
|
${u}
|
|
21
|
+
${d}
|
|
22
22
|
${f}
|
|
23
23
|
</body>
|
|
24
|
-
</html>`}function
|
|
24
|
+
</html>`}function Gt(e){return e._server=!0,e}var F=!(typeof process<"u");function oe(e){return e?e.dangerouslySetInnerHTML?e.dangerouslySetInnerHTML.__html??null:e.innerHTML&&typeof e.innerHTML=="object"&&"__html"in e.innerHTML?e.innerHTML.__html??null:(e.innerHTML!=null&&typeof e.innerHTML=="string"&&F&&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 ht=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,yt=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function ae(e){if(typeof e!="string"||!yt.test(e))throw new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(e)}`)}function se(e){let t="";for(let[n,r]of Object.entries(e)){if(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")continue;let o=n.toLowerCase();if(!(o.startsWith("on")&&n.length>2)){if(r===!1&&at(n)){t+=` ${n}="false"`;continue}if(!(r===!1||r==null)){if(!ht.test(n)){F&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(wt.has(o)){F&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")t+=` class="${g(String(r))}"`;else if(n==="style"&&typeof r=="object"){let s=Object.entries(r).map(([a,i])=>`${St(a)}:${i}`).join(";");t+=` style="${g(s)}"`}else if(r===!0)n.startsWith("aria-")||n==="role"?t+=` ${n}="true"`:t+=` ${n}`;else{if(mt(n,r))continue;t+=` ${n}="${g(String(r))}"`}}}}return t}function mt(e,t){let n=e.toLowerCase();if(!gt.has(n))return!1;let r=String(t).trim().replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();return r.startsWith("javascript:")||r.startsWith("vbscript:")||r.startsWith("data:")}var gt=new Set(["href","src","action","formaction","data","ping","xlink:href"]),wt=new Set(["srcdoc"]);function g(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function St(e){return e.startsWith("--")?e:e.replace(/([A-Z])/g,"-$1").toLowerCase()}var ie=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);export{me as ACTION_ENDPOINT,Je as Form,He as action,I as createActionHandler,ot as createCloudflareHandler,q as createRequestHandler,Z as csrfMetaTag,Kt as definePage,Ze as fetchActionHandler,pe as formAction,K as generateCsrfToken,Zt as generateStaticPage,Me as getRegisteredActions,$e as getRevalidationHandler,H as handleActionRequest,ye as invalidatePath,Ye as nodeActionMiddleware,je as onRevalidate,be as renderDocument,Yt as renderPage,ut as renderToHydratableString,$ as renderToStream,m as renderToString,ft as renderToStringAsync,Xt as renderToStringWithHead,W as revalidatePath,z as revalidateTag,J as serializeState,Gt as server,V as setRevalidationHandler,he as useAction,Le as useFormAction,Fe as useMutation,De as useOptimistic,le as validateCsrfToken};
|
package/dist/islands.min.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{mount as
|
|
1
|
+
import{mount as L,hydrate as N,signal as T,batch as O,getServerContext as j}from"what-core";var q=new RegExp("[<>&\\u2028\\u2029]","g"),F={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function I(e){return JSON.stringify(e).replace(q,n=>F[n.charCodeAt(0)])}var x=new Map,v=new Set,f=[],C=!1,E=new Map,g=new Map;function k(e){if(typeof structuredClone=="function")try{return structuredClone(e)}catch{}return Array.isArray(e)?e.map(k):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([n,t])=>[n,k(t)])):e}function b(e,n,t){if(e.has(n))return e.get(n);let r={},s={};for(let[o,a]of Object.entries(k(t)))s[o]=T(a),Object.defineProperty(r,o,{get:()=>s[o](),set:i=>s[o].set(i),enumerable:!0});return r._signals=s,r._subscribe=(o,a)=>{if(s[o])return s[o].subscribe(a)},r._batch=o=>O(o),r._getSnapshot=()=>{let o={};for(let[a,i]of Object.entries(s))o[a]=i.peek();return o},r._hydrate=o=>{O(()=>{for(let[a,i]of Object.entries(o))s[a]&&s[a].set(i)})},e.set(n,r),r}function w(e){let n=e||j();return n&&n.islandStores instanceof Map?n.islandStores:null}function M(e,n){if(g.has(e))return g.get(e).handle;let t={initialState:k(n),handle:null},r=()=>{let s=w();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 b(s,e,t.initialState)};return t.handle=new Proxy({},{get(s,o){return Reflect.get(r(),o)},set(s,o,a){return Reflect.set(r(),o,a)},has(s,o){return Reflect.has(r(),o)},ownKeys(){return Reflect.ownKeys(r())},getOwnPropertyDescriptor(s,o){let a=Reflect.getOwnPropertyDescriptor(r(),o);return a?{...a,configurable:!0}:void 0}}),g.set(e,t),t.handle}function W(e,n){if(typeof document<"u")return b(E,e,n);let t=w();if(t){let r=g.get(e);return b(t,e,r?.initialState??n)}return M(e,n)}function R(e,n={}){if(typeof document<"u")return b(E,e,n);let t=w();if(t){let r=g.get(e);return b(t,e,r?.initialState??n)}return M(e,n)}function V(){return I(D())}function D(e){let n=typeof document<"u"?E:w(e),t={};for(let[r,s]of n||[])t[r]=s._getSnapshot();return t}function J(e){try{let n=typeof e=="string"?JSON.parse(e):e;for(let[t,r]of Object.entries(n))R(t,r)._hydrate(r)}catch(n){console.warn("[what] Failed to hydrate island stores:",n)}}function U(e,n,t={}){x.set(e,{loader:n,mode:t.mode||"idle",media:t.media||null,priority:t.priority||0,stores:t.stores||[]})}function Y({name:e,props:n={},children:t,mode:r,priority:s,stores:o}){let a=x.get(e),i=r||a?.mode||"idle",c=s??a?.priority??0,d=o||a?.stores||[];return{tag:"div",props:{"data-island":e,"data-island-mode":i,"data-island-props":JSON.stringify(n),"data-island-priority":c,"data-island-stores":JSON.stringify(d)},children:t||[],key:null,_vnode:!0}}function h(e){let n=!1;for(let t=0;t<f.length;t++)if(e.priority>f[t].priority){f.splice(t,0,e),n=!0;break}n||f.push(e),_()}function _(){if(C||f.length===0)return;C=!0;let e=f.shift();Promise.resolve(e.hydrate()).catch(n=>console.error("[what] Island hydration failed:",e.name,n)).finally(()=>{C=!1,queueMicrotask(_)})}function Z(e,n=100){for(let t of f)if(t.name===e){t.priority=n,f.sort((r,s)=>s.priority-r.priority);break}}function A(){let e=document.getElementById("__what_data");if(e)try{let t=JSON.parse(e.textContent||"{}");t&&t.islandStores&&J(t.islandStores)}catch(t){console.warn("[what] Failed to parse hydration payload:",t)}let n=document.querySelectorAll("[data-island]");for(let t of n){if(t.dataset.islandSelf)continue;let r=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||"[]"),c=x.get(r);if(!c){console.warn(`[what] Island "${r}" not registered`);continue}v.has(t)||H(t,c,o,s,a,r,i)}}function H(e,n,t,r,s,o,a){let i=async()=>{if(v.has(e))return;v.add(e);let c=await n.loader(),d=c.default||c,u={};for(let y of a)u[y]=R(y);let p=d({...t,...u});e.childNodes.length>0?N(p,e):L(p,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:r}}))};switch(r){case"load":h({name:o,priority:s+1e3,hydrate:i});break;case"idle":"requestIdleCallback"in window?requestIdleCallback(()=>{h({name:o,priority:s,hydrate:i})}):setTimeout(()=>{h({name:o,priority:s,hydrate:i})},200);break;case"visible":{new IntersectionObserver((d,u)=>{for(let p of d)if(p.isIntersecting){u.disconnect(),h({name:o,priority:s,hydrate:i});break}},{rootMargin:"200px"}).observe(e);break}case"media":{let c=window.matchMedia(n.media||"(max-width: 768px)");c.matches?h({name:o,priority:s,hydrate:i}):c.addEventListener("change",d=>{d.matches&&h({name:o,priority:s,hydrate:i})},{once:!0});break}case"action":{let c=["click","focus","mouseover","touchstart"],d=()=>{c.forEach(u=>e.removeEventListener(u,d)),h({name:o,priority:s+500,hydrate:i})};c.forEach(u=>e.addEventListener(u,d,{once:!0,passive:!0}));break}case"static":break;default:h({name:o,priority:s,hydrate:i})}}function ee(e){for(let[n,t]of Object.entries(e))U(n,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",A):A())}function $(e,n){if(typeof document>"u")return;let t=document.querySelectorAll(e);for(let r of t)r.dataset.enhanced||(r.dataset.enhanced="true",n(r))}function Q(e){let n=document.querySelector('meta[name="csrf-token"]')||document.querySelector('meta[name="what-csrf-token"]');if(n)return n.getAttribute("content");let t=e.querySelector('input[name="what-csrf-token"], input[name="_csrf"]');if(t&&t.value)return t.value;let r=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return r?decodeURIComponent(r[1]):null}function X(e,n,t){let r=new FormData(e);if(n&&n.name&&r.append(n.name,n.value??""),t)return r;let s=new URLSearchParams,o=null;for(let[a,i]of r)typeof i=="string"?s.append(a,i.replace(/\r\n|\r|\n/g,`\r
|
|
2
|
+
`)):(o=o||a,s.append(a,i.name??""));return o&&typeof console<"u"&&console.warn(`[what] Form field "${o}" holds a file, but the form is not enctype="multipart/form-data", so only the file NAME is sent. This is what a plain HTML submit does too. Add enctype="multipart/form-data" to upload the bytes.`),s}function te(e="form[data-enhance]"){$(e,n=>{n.addEventListener("submit",async t=>{t.preventDefault();try{let r=t.submitter||null,s=l=>r&&r.getAttribute(`form${l}`)||n.getAttribute(l),o=(s("method")||"get").toUpperCase(),a=new URL(s("action")||location.href,location.href),c=(s("enctype")||"").toLowerCase()==="multipart/form-data",d=X(n,r,c),u=a.origin===location.origin,p={"X-Requested-With":"XMLHttpRequest"};if(u){let l=Q(n),S=n.getAttribute("data-no-csrf")==="true";if(!l&&!S){console.warn('[what] Form submission blocked: no CSRF token found. Add a <meta name="what-csrf-token"> tag (csrfMetaTag() emits it) or set data-no-csrf="true" on the form to opt out.'),n.dispatchEvent(new CustomEvent("form:error",{bubbles:!0,detail:{error:new Error("Missing CSRF token")}}));return}l&&(p["X-CSRF-Token"]=l)}let y;o==="GET"?a.search=String(d):c?y=d:(y=d,p["Content-Type"]="application/x-www-form-urlencoded;charset=UTF-8");let m=await fetch(a.href,{method:o,body:y,headers:p,credentials:"same-origin"}),P=new CustomEvent("form:response",{bubbles:!0,cancelable:!0,detail:{response:m,ok:m.ok,redirected:m.redirected}});if(n.dispatchEvent(P)&&m.ok&&m.redirected){let l=null;try{let S=new URL(m.url,location.href);S.origin===location.origin&&(l=S.href)}catch{}l&&location.assign(l)}}catch(r){n.dispatchEvent(new CustomEvent("form:error",{bubbles:!0,detail:{error:r}}))}})})}function ne(){let e=typeof document<"u"?[...E.keys()]:[...w()?.keys()||g.keys()];return{registered:[...x.keys()],hydrated:v.size,pending:f.length,queue:f.map(t=>({name:t.name,priority:t.priority})),stores:e}}export{Y as Island,ee as autoIslands,Z as boostIslandPriority,W as createIslandStore,$ as enhance,te as enhanceForms,ne as getIslandStatus,D as getIslandStoresSnapshot,J as hydrateIslandStores,A as hydrateIslands,U as island,V as serializeIslandStores,R as useIslandStore};
|
package/dist/node.min.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import{AsyncLocalStorage as Le}from"node:async_hooks";import{__installServerContextStorage as De}from"what-core";import{h as _t,_isAriaAttr as de,getServerContext as At,runWithServerContext as b,beginHeadCollection as fe,endHeadCollection as rt}from"what-core";var xt=new RegExp("[<>&\\u2028\\u2029]","g"),Pt={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function $(t){return JSON.stringify(t).replace(xt,e=>Pt[e.charCodeAt(0)])}import{mount as Ue,hydrate as Be,signal as Je,batch as Ve,getServerContext as $t}from"what-core";var Ht=new Map;function It(t){let e=t||$t();return e&&e.islandStores instanceof Map?e.islandStores:null}function lt(t){let e=typeof document<"u"?Ht:It(t),n={};for(let[r,o]of e||[])n[r]=o._getSnapshot();return n}import{signal as _,batch as Z}from"what-core";var T=null,pt=!(typeof process<"u");function X(t){T=t}function Nt(){return T}async function G(t,e){if(T&&T.revalidatePath)return T.revalidatePath(t,e);pt&&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 K(t,e){if(T&&T.revalidateTag)return T.revalidateTag(t,e);pt&&console.warn(`[what] revalidateTag('${t}') had no effect: no cache engine is bound.`)}var Q=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 ht(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 tt(t){return`<meta name="what-csrf-token" content="${String(t).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}var Lt=0,Dt=!1;function Mt(){return!Dt&&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${(++Lt).toString(36)}_${Date.now().toString(36)}`}`}function Ft(t,e={}){let n=e.id||Mt(),{onError:r,onSuccess:o,revalidate:a}=e;typeof window>"u"&&Q.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 f=jt(),l={"Content-Type":"application/json","X-What-Action":n};f&&(l["X-CSRF-Token"]=f);let p=await fetch("/__what_action",{method:"POST",headers:l,credentials:"same-origin",signal:u.signal,body:JSON.stringify({args:i})});if(!p.ok){let 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)gt(m);return h}catch(f){if(f.name==="AbortError"){let l=new Error(`Action "${n}" timed out after ${c}ms`);throw l.code="TIMEOUT",r&&r(l),l}throw r&&r(f),f}finally{clearTimeout(d)}}return s._actionId=n,s._isAction=!0,s}function mt(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,f]of s.entries())typeof File<"u"&&f instanceof File&&(u=!0),c[d]?Array.isArray(c[d])?c[d].push(f):c[d]=[c[d],f]:c[d]=f;try{let d=u?await t(c,s):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(...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 Ut(t,e={}){let{resetOnSuccess:n=!0}=e,r={current:null},o=yt(mt(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 Bt(t,e){let n=_(t),r=_([]),o=_(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(f=>f!==u)),d!==void 0){o.set(d);let f=d;for(let l of r.peek())f=e(f,l);n.set(f)}})}function i(u,d){Z(()=>{let f=r.peek().filter(h=>h!==u);r.set(f);let l=d!==void 0?d:o.peek();o.set(l);let p=l;for(let h of f)p=e(p,h);n.set(p)})}async function c(u,d){a(u);try{let f=await d();return s(u,f),f}catch(f){throw i(u),f}}return{value:()=>n(),isPending:()=>r().length>0,addOptimistic:a,resolve:s,rollback:i,withOptimistic:c,set:u=>{n.set(u),o.set(u)}}}var H=new Map;function Jt(t,e){return H.has(t)||H.set(t,new Set),H.get(t).add(e),()=>{H.get(t)?.delete(e)}}function gt(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: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(!ht(i,o))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let s=Q.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 G(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await K(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 Vt(){return[...Q.keys()]}function Wt(t,e={}){let{onSuccess:n,onError:r,onSettled:o}=e,a={isPending:_(!1),error:_(null),data:_(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)}}}import{h as M}from"what-core";var wt="/__what_action";function zt(t){if(typeof t=="string")return t;if(typeof t=="function"){let e=t._actionId;if(e)return e;throw new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string.")}throw new Error("[what] <Form> requires an `action` prop: a server action or its id.")}function Yt(){if(typeof document>"u")return null;let t=document.querySelector('meta[name="what-csrf-token"]');if(t)return t.getAttribute("content");let e=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return e?decodeURIComponent(e[1]):null}function Xt({action:t,csrfToken:e,redirect:n,method:r="post",enhance:o=!0,children:a,...s}){let i=zt(t),c=e!==void 0?e:Yt();c==null&&typeof process<"u";let u=[M("input",{type:"hidden",name:"_action",value:i}),M("input",{type:"hidden",name:"what-csrf-token",value:c||""})];n&&u.push(M("input",{type:"hidden",name:"_redirect",value:n}));let d={...s,method:r,action:s.action||wt,"data-action":i};o&&(d["data-enhance"]="");let f=a==null?[]:Array.isArray(a)?a:[a];return M("form",d,...u,...f)}var Gt="/__what_action",I=1024*1024;function Kt(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 F(t,e){return{status:t,headers:{"content-type":"application/json"},body:JSON.stringify(e)}}function et(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 St(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=St(t&&t._redirect);if(n)return n;let r=e.referer||e.referrer;if(r)try{let o=new URL(r,"http://localhost"),a=St(o.pathname+o.search);if(a)return a}catch{}return"/"}var Qt=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function N(t={}){let{getCsrfToken:e,skipCsrf:n=!1}=t;return async function(o){if((o.method||"POST").toUpperCase()!=="POST")return F(405,{message:"Method Not Allowed"});let s=Kt(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 et(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let S={...s},E=h._csrf??h["what-csrf-token"];if(E&&!S["x-csrf-token"]&&(S["x-csrf-token"]=String(E)),!n&&e&&!d)return et(403,"Missing CSRF token");let C={};for(let[O,z]of Object.entries(h))Qt.has(O)||(C[O]=z);let v=await D({headers:S},m,[C],{csrfToken:d,skipCsrf:n});return v.status===200?{status:303,headers:{location:Zt(h,s)},body:""}:et(v.status,v.body&&v.body.message||"Action failed")}if(!i)return F(400,{message:"Missing X-What-Action header"});if(!n&&e&&!d)return F(403,{message:"Missing CSRF token"});let l=(o.body||{}).args,p=await D({headers:s},i,l,{csrfToken:d,skipCsrf:n});return F(p.status,p.body)}}function qt(t={}){let e=t.basePath||Gt,n=N(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 l=await te(o);u=U(l,o.headers["content-type"]||"")}catch(l){a.writeHead(l.code==="BODY_TOO_LARGE"?413:400,{"content-type":"application/json"}),a.end(JSON.stringify({message:l.code==="BODY_TOO_LARGE"?"Payload too large":"Invalid request body"}));return}let d=Object.fromEntries(new URLSearchParams(c||"")),f=await n({method:o.method,headers:o.headers,body:u,query:d});a.writeHead(f.status,f.headers),a.end(f.body)}}function U(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 B(t,e=I){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 te(t){return new Promise((e,n)=>{let r=0,o=[];t.on("data",a=>{if(r+=a.length,r>I){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 ee(t={}){let e=N(t);return async function(n){let r={};try{let s=await B(n);if(s.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=U(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 ne,parseQuery as re}from"what-router/match";var oe="/__what_action",ae="/__what_revalidate",nt="what-csrf";function j(t){let e={};return t&&typeof t.forEach=="function"&&t.forEach((n,r)=>{e[r.toLowerCase()]=n}),e}function bt(t,e){if(!t)return null;let n=String(t).match(new RegExp(`(?:^|;\\s*)${e}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function se(t){try{let e=await B(t);return e.tooLarge?{tooLarge:!0}:U(e.raw,t.headers.get("content-type")||"")}catch{return{}}}async function ie(t){let e;try{e=await B(t)}catch{return{json:{}}}if(e.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(e.raw)}}catch{return{json:{}}}}function ce(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 J(i,{params:o,query:a,request:s},c),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function R(t={}){let{routes:e=[],cache:n,render:r,revalidateWebhook:o,document:a={},notFound:s,basePath:i="",csrf:c=!0}=t,u=c!==!1&&!t.actionHandler,d=t.actionHandler||N(u?{getCsrfToken:l=>bt(l.headers&&l.headers.cookie,nt)}:{skipCsrf:!0}),f=r||ce(a);return n&&(n.revalidatePath||n.revalidateTag)&&X({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===oe){let y=await se(p);if(y&&y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await d({method:"POST",headers:j(p.headers),body:y,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let S=null,E=null;if(u&&(S=bt(j(p.headers).cookie,nt),!S)){S=q();let A=j(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;E=`${nt}=${encodeURIComponent(S)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let C=y=>(E&&(y["set-cookie"]=E),y);if(p.method==="POST"&&m===ae&&o){let y=await ie(p);if(y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await o({headers:j(p.headers),body:y.json});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let v=ne(m,e);if(!v){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:O,params:z}=v,Y=O.page||{mode:O.mode||"client"},P={path:m,query:re(h.search),config:Y,route:O,params:z,request:p};if(n&&Y.mode!=="server"){P.varyHeaders=j(p.headers);let y=await n.handle(P,()=>f(P));return new Response(y.html,{status:y.status||200,headers:C({"content-type":"text/html; charset=utf-8",...y.headers||{}})})}S&&(P.csrfToken=S);let dt=await f(P),ft=C({"content-type":"text/html; charset=utf-8"});return Y.mode==="server"&&(ft["Cache-Control"]="private, no-store"),new Response(dt.html,{status:dt.status||200,headers:ft})}}function ue(t={}){let e=R(t);return{async fetch(n,r,o){return r&&(n.__env=r),o&&(n.__ctx=o),e(n)}}}function k(t){return{head:fe(),loaderData:t,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var Tt=0;function le(){Tt=0}function pe(){return"h"+Tt++}function he(t){if(!At()){let e=k(void 0);return b(e,()=>he(t))}return le(),x(t)}function x(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`<!--$-->${x(t())}<!--/$-->`;if(typeof t=="function")try{return`<!--$-->${x(t())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(t))return`<!--[]-->${t.map(x).join("")}<!--/[]-->`;if(typeof t.tag=="function"){let c=pe(),u=t.tag({...t.props,children:t.children}),d=x(u);return me(d,c)}let{tag:e,props:n,children:r}=t;at(e);let o=st(n||{}),a=`<${e}${o}>`;if(it.has(e))return a;let s=ot(n),i=s!=null?String(s):r.map(x).join("");return`${a}${i}</${e}>`}function me(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 w(t){if(!At()){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;at(e);let o=st(n||{}),a=`<${e}${o}>`;if(it.has(e))return a;let s=ot(n),i=s!=null?String(s):r.map(w).join("");return`${a}${i}</${e}>`}function pn(t){let e=k(void 0);return{body:b(e,()=>w(t)),head:rt(e.head)}}async function hn(t,e={}){let n=t.default||t,r=typeof t.loader=="function"?await t.loader(e):void 0,o=k(r),a=e.params||{};return{body:b(o,()=>w(_t(n,{...a,loaderData:r}))),head:rt(o.head),loaderData:r}}var Rt=12;async function ye(t,e){e||(e=k(void 0));let n="";for(let o=0;o<Rt;o++){n=b(e,()=>w(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:rt(e.head),loaderData:e.loaderData,resources:r,ctx:e}}async function J(t,e={},n={}){let r=t.default||t,o=typeof t.loader=="function"?await t.loader(e):void 0,a=k(o),s=e.params||{},{body:i,head:c,resources:u}=await ye(_t(r,{...s,loaderData:o}),a),d={loaderData:o??null,resources:u,islandStores:lt(a)};return ge({body:i,head:c,payload:d,options:n})}function ge({body:t,head:e,payload:n,options:r={}}){let o=r.lang||"en",a=`<script id="__what_data" type="application/json">${$(n)}<\/script>`,s=r.clientEntry?`<script type="module" src="${g(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?tt(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*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 s=b(e,()=>t());yield*L(s,e);return}if(typeof t=="function"){try{let s=b(e,()=>t());yield*L(s,e)}catch{typeof process<"u"}return}if(Array.isArray(t)){for(let s of t)yield*L(s,e);return}if(t.tag==="__suspense"){let s=null;for(let i=0;i<Rt&&s===null;i++){let c=null;try{s=b(e,()=>(t.children||[]).map(w).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=b(e,()=>w(t.props&&t.props.fallback))),yield s;return}if(typeof t.tag=="function"){try{let s=b(e,()=>t.tag({...t.props,children:t.children})),i=s instanceof Promise?await s:s;yield*L(i,e)}catch(s){typeof process<"u",yield V?`<!-- SSR Error: ${g(s.message||"Component error")} -->`:"<!-- SSR Error -->"}return}let{tag:n,props:r,children:o}=t;at(n);let a=st(r||{});if(yield`<${n}${a}>`,!it.has(n)){let s=ot(r);if(s!=null)yield String(s);else for(let i of o)yield*L(i,e);yield`</${n}>`}}function mn(t){return{mode:"static",...t}}function yn(t,e={}){let n=k(e),r=b(n,()=>{let a=t.component(e);return w(a)}),o=t.islands||[];return we({title:t.title||"",meta:t.meta||{},body:r,islands:o,scripts:t.mode==="static"?[]:t.scripts||[],styles:t.styles||[],mode:t.mode})}function we({title:t,meta:e,body:n,islands:r,scripts:o,styles:a,mode:s}){let i=Object.entries(e).map(([l,p])=>`<meta name="${g(l)}" content="${g(p)}">`).join(`
|
|
2
|
-
`),c=a.map(
|
|
1
|
+
import{AsyncLocalStorage as Ft}from"node:async_hooks";import{__installServerContextStorage as Ut}from"what-core";import{h as Re,_isAriaAttr as pt,_beginComponentSSR as re,_endComponentSSR as oe,_mapArrayToArray as ae,getServerContext as ke,runWithServerContext as b,beginHeadCollection as ht,endHeadCollection as se}from"what-core";var Ne=new RegExp("[<>&\\u2028\\u2029]","g"),He={60:"\\u003c",62:"\\u003e",38:"\\u0026",8232:"\\u2028",8233:"\\u2029"};function N(e){return JSON.stringify(e).replace(Ne,t=>He[t.charCodeAt(0)])}import{mount as Jt,hydrate as Wt,signal as zt,batch as Yt,getServerContext as Ie}from"what-core";var je=new Map;function Le(e){let t=e||Ie();return t&&t.islandStores instanceof Map?t.islandStores:null}function me(e){let t=typeof document<"u"?je:Le(e),n={};for(let[r,o]of t||[])n[r]=o._getSnapshot();return n}import{signal as _,batch as Z}from"what-core";var T=null,ye=!(typeof process<"u");function X(e){T=e}function De(){return T}async function G(e,t){if(T&&T.revalidatePath)return T.revalidatePath(e,t);ye&&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 K(e,t){if(T&&T.revalidateTag)return T.revalidateTag(e,t);ye&&console.warn(`[what] revalidateTag('${e}') had no effect: no cache engine is bound.`)}var Q=new Map;function Me(){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 q(){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 ge(e,t){if(!e||!t||e.length!==t.length)return!1;let n=0;for(let r=0;r<e.length;r++)n|=e.charCodeAt(r)^t.charCodeAt(r);return n===0}function ee(e){return`<meta name="what-csrf-token" content="${String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}">`}var Fe=0,Ue=!1;function Be(){return!Ue&&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${(++Fe).toString(36)}_${Date.now().toString(36)}`}`}function Ve(e,t={}){let n=t.id||Be(),{onError:r,onSuccess:o,revalidate:a}=t;typeof window>"u"&&Q.set(n,{fn:e,options:t});async function s(...i){if(typeof window>"u")return e(...i);let c=t.timeout||3e4,u=new AbortController,d=setTimeout(()=>u.abort(),c);try{let l=Me(),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)be(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 we(e,t={}){let{onSuccess:n,onError:r,resetOnSuccess:o=!0}=t;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 e(c,s):await e(c);return n&&n(d,i),o&&i&&i.reset(),d}catch(d){throw r&&r(d,i),d}}}function Se(e){let t=_(!1),n=_(null),r=_(null);async function o(...a){t.set(!0),n.set(null);try{let s=await e(...a);return r.set(s),s}catch(s){throw n.set(s),s}finally{t.set(!1)}}return{trigger:o,isPending:()=>t(),error:()=>n(),data:()=>r(),reset:()=>{n.set(null),r.set(null)}}}function Je(e,t={}){let{resetOnSuccess:n=!0}=t,r={current:null},o=Se(we(e,{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 We(e,t){let n=_(e),r=_([]),o=_(e);function a(u){let d=t(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=t(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=t(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 H=new Map;function ze(e,t){return H.has(e)||H.set(e,new Set),H.get(e).add(t),()=>{H.get(e)?.delete(t)}}function be(e){let t=H.get(e);if(t)for(let n of t)try{n()}catch(r){console.error("[what] Revalidation error:",r)}}function D(e,t,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=e?.headers?.["x-csrf-token"]||e?.headers?.["X-CSRF-Token"];if(!ge(i,o))return Promise.resolve({status:403,body:{message:"Invalid CSRF token"}})}let s=Q.get(t);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 G(u);if(Array.isArray(c.revalidateTags))for(let u of c.revalidateTags)await K(u);return{status:200,body:i}}).catch(i=>(console.error(`[what] Action "${t}" error:`,i),{status:500,body:{message:"Action failed"}})):Promise.resolve({status:400,body:{message:"Invalid action arguments"}}):Promise.resolve({status:404,body:{message:"Action not found"}})}function Ye(){return[...Q.keys()]}function Xe(e,t={}){let{onSuccess:n,onError:r,onSettled:o}=t,a={isPending:_(!1),error:_(null),data:_(null)};async function s(...i){a.isPending.set(!0),a.error.set(null);try{let c=await e(...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)}}}import{h as M}from"what-core";var _e="/__what_action";function Ge(e){if(typeof e=="string")return e;if(typeof e=="function"){let t=e._actionId;if(t)return t;throw new Error("[what] <Form action={fn}>: that function is not a server action. Wrap it with action() from what-server, or pass the action id as a string.")}throw new Error("[what] <Form> requires an `action` prop: a server action or its id.")}function Ke(){if(typeof document>"u")return null;let e=document.querySelector('meta[name="what-csrf-token"]');if(e)return e.getAttribute("content");let t=document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);return t?decodeURIComponent(t[1]):null}function Ze({action:e,csrfToken:t,redirect:n,method:r="post",enhance:o=!0,children:a,...s}){let i=Ge(e),c=t!==void 0?t:Ke();c==null&&typeof process<"u";let u=[M("input",{type:"hidden",name:"_action",value:i}),M("input",{type:"hidden",name:"what-csrf-token",value:c||""})];n&&u.push(M("input",{type:"hidden",name:"_redirect",value:n}));let d={...s,method:r,action:s.action||_e,"data-action":i};o&&(d["data-enhance"]="");let l=a==null?[]:Array.isArray(a)?a:[a];return M("form",d,...u,...l)}var Qe="/__what_action",I=1024*1024;function qe(e){if(!e)return{};if(typeof e.forEach=="function"&&typeof e.get=="function"){let n={};return e.forEach((r,o)=>{n[o.toLowerCase()]=r}),n}let t={};for(let n in e)t[n.toLowerCase()]=e[n];return t}function F(e,t){return{status:e,headers:{"content-type":"application/json"},body:JSON.stringify(t)}}function te(e,t){return{status:e,headers:{"content-type":"text/html; charset=utf-8"},body:`<!DOCTYPE html><html><body><h1>${e}</h1><p>${String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}</p></body></html>`}}function Ae(e){if(typeof e!="string"||!e.startsWith("/")||/^[/\\]{2}/.test(e)||e.includes("\\"))return null;try{let t=new URL(e,"http://localhost");return t.origin!=="http://localhost"?null:t.pathname+t.search}catch{return null}}function et(e,t){let n=Ae(e&&e._redirect);if(n)return n;let r=t.referer||t.referrer;if(r)try{let o=new URL(r,"http://localhost"),a=Ae(o.pathname+o.search);if(a)return a}catch{}return"/"}var tt=new Set(["_action","data-action","_csrf","what-csrf-token","_redirect"]);function j(e={}){let{getCsrfToken:t,skipCsrf:n=!1}=e;return async function(o){if((o.method||"POST").toUpperCase()!=="POST")return F(405,{message:"Method Not Allowed"});let s=qe(o.headers),i=s["x-what-action"],c=s["content-type"]||"",u=!i&&c.includes("application/x-www-form-urlencoded"),d=n?void 0:t?await t(o):void 0;if(u){let h=o.body||{},m=h._action||h["data-action"]||o.query&&o.query.action;if(!m)return te(400,'Missing action name (add a hidden "_action" field or ?action= query param)');let S={...s},C=h._csrf??h["what-csrf-token"];if(C&&!S["x-csrf-token"]&&(S["x-csrf-token"]=String(C)),!n&&t&&!d)return te(403,"Missing CSRF token");let O={};for(let[x,z]of Object.entries(h))tt.has(x)||(O[x]=z);let E=await D({headers:S},m,[O],{csrfToken:d,skipCsrf:n});return E.status===200?{status:303,headers:{location:et(h,s)},body:""}:te(E.status,E.body&&E.body.message||"Action failed")}if(!i)return F(400,{message:"Missing X-What-Action header"});if(!n&&t&&!d)return F(403,{message:"Missing CSRF token"});let f=(o.body||{}).args,p=await D({headers:s},i,f,{csrfToken:d,skipCsrf:n});return F(p.status,p.body)}}function nt(e={}){let t=e.basePath||Qe,n=j(e);return async function(o,a,s){let[i,c]=(o.url||"").split("?");if(i!==t||(o.method||"").toUpperCase()!=="POST")return s?s():void 0;let u;try{let f=await rt(o);u=U(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 U(e,t){if((t||"").includes("application/x-www-form-urlencoded")){let n={};for(let[r,o]of new URLSearchParams(String(e)))n[r]===void 0?n[r]=o:Array.isArray(n[r])?n[r].push(o):n[r]=[n[r],o];return n}return e==null||e===""?{}:JSON.parse(String(e))}async function B(e,t=I){let n=Number(e.headers.get("content-length"));if(Number.isFinite(n)&&n>t)return{tooLarge:!0};let r=e.body;if(!r||typeof r.getReader!="function"){let i=await e.text();return Buffer.byteLength(i,"utf8")>t?{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>t){try{await o.cancel()}catch{}return{tooLarge:!0}}a.push(c)}}return{raw:Buffer.concat(a.map(i=>Buffer.from(i))).toString("utf8")}}function rt(e){return new Promise((t,n)=>{let r=0,o=[];e.on("data",a=>{if(r+=a.length,r>I){let s=new Error("Body too large");s.code="BODY_TOO_LARGE",n(s),e.destroy?.();return}o.push(a)}),e.on("end",()=>{if(o.length===0)return t("");t(Buffer.concat(o).toString("utf8"))}),e.on("error",n)})}function ot(e={}){let t=j(e);return async function(n){let r={};try{let s=await B(n);if(s.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});r=U(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 t({method:n.method,headers:n.headers,body:r,query:o});return new Response(a.body,{status:a.status,headers:a.headers})}}import{matchRoute as at,parseQuery as st}from"what-router/match";var it="/__what_action",ct="/__what_revalidate",ne="what-csrf";function L(e){let t={};return e&&typeof e.forEach=="function"&&e.forEach((n,r)=>{t[r.toLowerCase()]=n}),t}function Te(e,t){if(!e)return null;let n=String(e).match(new RegExp(`(?:^|;\\s*)${t}=([^;]+)`));return n?decodeURIComponent(n[1]):null}async function ut(e){try{let t=await B(e);return t.tooLarge?{tooLarge:!0}:U(t.raw,e.headers.get("content-type")||"")}catch{return{}}}async function dt(e){let t;try{t=await B(e)}catch{return{json:{}}}if(t.tooLarge)return{tooLarge:!0};try{return{json:JSON.parse(t.raw)}}catch{return{json:{}}}}function lt(e){return async function(n){let{route:r,params:o,query:a,request:s}=n,i={default:r.component,loader:r.loader},c=n.csrfToken?{...e,csrfToken:n.csrfToken}:e;return{html:await V(i,{params:o,query:a,request:s},c),status:200,tags:n.config&&n.config.tags||[],path:n.path}}}function R(e={}){let{routes:t=[],cache:n,render:r,revalidateWebhook:o,document:a={},notFound:s,basePath:i="",csrf:c=!0}=e,u=c!==!1&&!e.actionHandler,d=e.actionHandler||j(u?{getCsrfToken:f=>Te(f.headers&&f.headers.cookie,ne)}:{skipCsrf:!0}),l=r||lt(a);return n&&(n.revalidatePath||n.revalidateTag)&&X({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===it){let y=await ut(p);if(y&&y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await d({method:"POST",headers:L(p.headers),body:y,query:Object.fromEntries(h.searchParams)});return new Response(A.body,{status:A.status,headers:A.headers})}let S=null,C=null;if(u&&(S=Te(L(p.headers).cookie,ne),!S)){S=q();let A=L(p.headers)["x-forwarded-proto"]==="https"||h.protocol==="https:"||!0;C=`${ne}=${encodeURIComponent(S)}; Path=/; SameSite=Lax`+(A?"; Secure":"")}let O=y=>(C&&(y["set-cookie"]=C),y);if(p.method==="POST"&&m===ct&&o){let y=await dt(p);if(y.tooLarge)return new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});let A=await o({headers:L(p.headers),body:y.json});return new Response(JSON.stringify(A.body),{status:A.status,headers:{"content-type":"application/json"}})}let E=at(m,t);if(!E){let y=s?s():"<!DOCTYPE html><html><body><h1>404 \u2014 Not Found</h1></body></html>";return new Response(y,{status:404,headers:O({"content-type":"text/html; charset=utf-8"})})}let{route:x,params:z}=E,Y=x.page||{mode:x.mode||"client"},P={path:m,query:st(h.search),config:Y,route:x,params:z,request:p};if(n&&Y.mode!=="server"){P.varyHeaders=L(p.headers);let y=await n.handle(P,()=>l(P));return new Response(y.html,{status:y.status||200,headers:O({"content-type":"text/html; charset=utf-8",...y.headers||{}})})}S&&(P.csrfToken=S);let pe=await l(P),he=O({"content-type":"text/html; charset=utf-8"});return Y.mode==="server"&&(he["Cache-Control"]="private, no-store"),new Response(pe.html,{status:pe.status||200,headers:he})}}function ft(e={}){let t=R(e);return{async fetch(n,r,o){return r&&(n.__env=r),o&&(n.__ctx=o),t(n)}}}function k(e){return{head:ht(),loaderData:e,resources:new Map,islandStores:new Map,resourceCounter:0,boundaryCounter:0,suspended:[]}}var Ee=0;function mt(){Ee=0}function yt(){return"h"+Ee++}function gt(e){if(!ke()){let t=k(void 0);return b(t,()=>gt(e))}return mt(),v(e)}function v(e){if(e==null||e===!1||e===!0)return"";if(typeof e=="string"||typeof e=="number")return w(String(e));if(typeof e=="function"&&e._signal)return`<!--$-->${v(e())}<!--/$-->`;if(typeof e=="function"&&e._mapArray)try{return`<!--$-->${v(ae(e))}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(typeof e=="function")try{return`<!--$-->${v(e())}<!--/$-->`}catch{return typeof process<"u","<!--$--><!--/$-->"}if(Array.isArray(e))return`<!--[]-->${e.map(v).join("")}<!--/[]-->`;if(typeof e.tag=="function"){let c=yt(),u=re(e.tag),d;try{d=v(e.tag({...e.props,children:e.children}))}finally{oe(u)}return wt(d,c)}let{tag:t,props:n,children:r}=e;ce(t);let o=ue(n||{}),a=`<${t}${o}>`;if(de.has(t))return a;let s=ie(n),i=s!=null?String(s):r.map(v).join("");return`${a}${i}</${t}>`}function wt(e,t){let n=e.match(/^((?:<!--.*?-->)*)<([a-zA-Z][a-zA-Z0-9-]*)/);if(n){let r=n[1],o=n[2],a=r.length+1+o.length;return e.slice(0,a)+` data-hk="${t}"`+e.slice(a)}return e}function g(e){if(!ke()){let c=k(void 0);return b(c,()=>g(e))}if(e==null||e===!1||e===!0)return"";if(typeof e=="string"||typeof e=="number")return w(String(e));if(typeof e=="function"&&e._signal)return g(e());if(typeof e=="function"&&e._mapArray)try{return g(ae(e))}catch{return typeof process<"u",""}if(typeof e=="function")try{return g(e())}catch{return typeof process<"u",""}if(Array.isArray(e))return e.map(g).join("");if(e.tag==="__suspense")try{return(e.children||[]).map(g).join("")}catch(c){if(c&&typeof c.then=="function")return g(e.props&&e.props.fallback);throw c}if(typeof e.tag=="function"){let c=re(e.tag);try{return g(e.tag({...e.props,children:e.children}))}finally{oe(c)}}let{tag:t,props:n,children:r}=e;ce(t);let o=ue(n||{}),a=`<${t}${o}>`;if(de.has(t))return a;let s=ie(n),i=s!=null?String(s):r.map(g).join("");return`${a}${i}</${t}>`}function yn(e){let t=k(void 0);return{body:b(t,()=>g(e)),head:se(t.head)}}async function gn(e,t={}){let n=e.default||e,r=typeof e.loader=="function"?await e.loader(t):void 0,o=k(r),a=t.params||{};return{body:b(o,()=>g(Re(n,{...a,loaderData:r}))),head:se(o.head),loaderData:r}}var ve=12;async function St(e,t){t||(t=k(void 0));let n="";for(let o=0;o<ve;o++){n=b(t,()=>g(e));let a=[...t.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 t.resources)a.status==="ready"&&(r[o]=a.value);return{body:n,head:se(t.head),loaderData:t.loaderData,resources:r,ctx:t}}async function V(e,t={},n={}){let r=e.default||e,o=typeof e.loader=="function"?await e.loader(t):void 0,a=k(o),s=t.params||{},{body:i,head:c,resources:u}=await St(Re(r,{...s,loaderData:o}),a),d={loaderData:o??null,resources:u,islandStores:me(a)};return bt({body:i,head:c,payload:d,options:n})}function bt({body:e,head:t,payload:n,options:r={}}){let o=r.lang||"en",a=`<script id="__what_data" type="application/json">${N(n)}<\/script>`,s=r.clientEntry?`<script type="module" src="${w(r.clientEntry)}"><\/script>`:"",c=(r.csrfToken?ee(r.csrfToken):"")+(r.head||""),u=r.bodyClass?` class="${w(r.bodyClass)}"`:"";return`<!DOCTYPE html><html lang="${w(o)}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${t||""}${c}</head><body${u}>${e}${a}${s}</body></html>`}async function*$(e,t){if(t===void 0&&(t=k(void 0)),e==null||e===!1||e===!0)return;if(typeof e=="string"||typeof e=="number"){yield w(String(e));return}if(typeof e=="function"&&e._signal){let s=b(t,()=>e());yield*$(s,t);return}if(typeof e=="function"&&e._mapArray){let s=null;try{s=b(t,()=>ae(e))}catch{typeof process<"u"}s&&(yield*$(s,t));return}if(typeof e=="function"){try{let s=b(t,()=>e());yield*$(s,t)}catch{typeof process<"u"}return}if(Array.isArray(e)){for(let s of e)yield*$(s,t);return}if(e.tag==="__suspense"){let s=null;for(let i=0;i<ve&&s===null;i++){let c=null;try{s=b(t,()=>(e.children||[]).map(g).join(""))}catch(u){if(u&&typeof u.then=="function")c=u;else throw u}if(s===null){let u=[...t.resources.values()].filter(d=>d.status==="pending").map(d=>d.promise);await Promise.all([c,...u].filter(Boolean))}}s===null&&(s=b(t,()=>g(e.props&&e.props.fallback))),yield s;return}if(typeof e.tag=="function"){let s=re(e.tag);try{let i=b(t,()=>e.tag({...e.props,children:e.children})),c=i instanceof Promise?await i:i;yield*$(c,t)}catch(i){typeof process<"u",yield J?`<!-- SSR Error: ${w(i.message||"Component error")} -->`:"<!-- SSR Error -->"}finally{oe(s)}return}let{tag:n,props:r,children:o}=e;ce(n);let a=ue(r||{});if(yield`<${n}${a}>`,!de.has(n)){let s=ie(r);if(s!=null)yield String(s);else for(let i of o)yield*$(i,t);yield`</${n}>`}}function wn(e){return{mode:"static",...e}}function Sn(e,t={}){let n=k(t),r=b(n,()=>{let a=e.component(t);return g(a)}),o=e.islands||[];return _t({title:e.title||"",meta:e.meta||{},body:r,islands:o,scripts:e.mode==="static"?[]:e.scripts||[],styles:e.styles||[],mode:e.mode})}function _t({title:e,meta:t,body:n,islands:r,scripts:o,styles:a,mode:s}){let i=Object.entries(t).map(([f,p])=>`<meta name="${w(f)}" content="${w(p)}">`).join(`
|
|
2
|
+
`),c=a.map(f=>`<link rel="stylesheet" href="${w(f)}">`).join(`
|
|
3
3
|
`),u=r.length>0?`
|
|
4
4
|
<script type="module">
|
|
5
5
|
import { hydrateIslands } from '/@what/islands.js';
|
|
6
6
|
hydrateIslands();
|
|
7
|
-
<\/script>`:"",d=o.map(
|
|
8
|
-
`),
|
|
7
|
+
<\/script>`:"",d=o.map(f=>`<script type="module" src="${w(f)}"><\/script>`).join(`
|
|
8
|
+
`),l=s==="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>${w(e)}</title>
|
|
16
16
|
${c}
|
|
17
17
|
</head>
|
|
18
18
|
<body>
|
|
19
19
|
<div id="app">${n}</div>
|
|
20
20
|
${u}
|
|
21
21
|
${d}
|
|
22
|
-
${
|
|
22
|
+
${l}
|
|
23
23
|
</body>
|
|
24
|
-
</html>`}function
|
|
24
|
+
</html>`}function bn(e){return e._server=!0,e}var J=!(typeof process<"u");function ie(e){return e?e.dangerouslySetInnerHTML?e.dangerouslySetInnerHTML.__html??null:e.innerHTML&&typeof e.innerHTML=="object"&&"__html"in e.innerHTML?e.innerHTML.__html??null:(e.innerHTML!=null&&typeof e.innerHTML=="string"&&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 At=/^[a-zA-Z_:][a-zA-Z0-9:._-]*$/,Tt=/^[a-zA-Z_][a-zA-Z0-9._:-]*$/;function ce(e){if(typeof e!="string"||!Tt.test(e))throw new Error(`[what-server] Invalid tag name in SSR: ${JSON.stringify(e)}`)}function ue(e){let t="";for(let[n,r]of Object.entries(e)){if(n==="key"||n==="ref"||n==="children"||n==="dangerouslySetInnerHTML"||n==="innerHTML")continue;let o=n.toLowerCase();if(!(o.startsWith("on")&&n.length>2)){if(r===!1&&pt(n)){t+=` ${n}="false"`;continue}if(!(r===!1||r==null)){if(!At.test(n)){J&&console.warn(`[what-server] Skipping invalid attribute name in SSR: ${JSON.stringify(n)}`);continue}if(Et.has(o)){J&&console.warn(`[what-server] Skipping unsafe attribute in SSR: ${JSON.stringify(n)}`);continue}if(n==="className"||n==="class")t+=` class="${w(String(r))}"`;else if(n==="style"&&typeof r=="object"){let a=Object.entries(r).map(([s,i])=>`${vt(s)}:${i}`).join(";");t+=` style="${w(a)}"`}else if(r===!0)n.startsWith("aria-")||n==="role"?t+=` ${n}="true"`:t+=` ${n}`;else{if(Rt(n,r))continue;t+=` ${n}="${w(String(r))}"`}}}}return t}function Rt(e,t){let n=e.toLowerCase();if(!kt.has(n))return!1;let r=String(t).trim().replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();return r.startsWith("javascript:")||r.startsWith("vbscript:")||r.startsWith("data:")}var kt=new Set(["href","src","action","formaction","data","ping","xlink:href"]),Et=new Set(["srcdoc"]);function w(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function vt(e){return e.startsWith("--")?e:e.replace(/([A-Z])/g,"-$1").toLowerCase()}var de=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);import Ct from"node:http";var le=Symbol("what.bodyTooLarge"),Ce=()=>new Response(JSON.stringify({message:"Payload too large"}),{status:413,headers:{"content-type":"application/json"}});async function Oe(e){let n=`http://${e.headers.host||"localhost"}${e.url}`,r=new Headers;for(let[a,s]of Object.entries(e.headers))s!=null&&r.set(a,Array.isArray(s)?s.join(", "):String(s));let o;if(e.method!=="GET"&&e.method!=="HEAD"){let a=Number(e.headers["content-length"]),s=Number.isFinite(a)&&a>I,i=[],c=0;for await(let u of e)if(!s){if(c+=u.length,c>I){s=!0,i.length=0;continue}i.push(u)}if(s)return le;i.length&&(o=Buffer.concat(i))}return new Request(n,{method:e.method,headers:r,body:o})}async function W(e,t){e.statusCode=t.status,t.headers.forEach((r,o)=>e.setHeader(o,r));let n=await t.text();e.end(n)}function xe(e){return async function(n,r){try{let o=await Oe(n);if(o===le)return await W(r,Ce());let a=await e(o);await W(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 Ot(e={}){let t=R(e);return async function(r,o,a){let s=await Oe(r);if(s===le)return await W(o,Ce());let i=await t(s);if(i.status===404&&typeof a=="function")return a();await W(o,i)}}function xt(e={}){let t=R(e),n=Ct.createServer(xe(t)),{scheduler:r}=e;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 $t,writeFile as $e}from"node:fs/promises";import{join as fe,resolve as Pe,sep as Pt}from"node:path";import{matchRoute as Nt}from"what-router/match";function Ht(e){return e.includes(":")||e.includes("*")||e.includes("[")}function It(e,t){return e.replace(/\[\.\.\.(\w+)\]/g,(n,r)=>t[r]??"").replace(/\[(\w+)\]/g,(n,r)=>t[r]??"").replace(/[:*](\w+)/g,(n,r)=>t[r]??"")}function jt(e,t){let n=Pe(e),r=Pe(fe(e,t==="/"?"":t));if(r!==n&&!r.startsWith(n+Pt))throw new Error(`[what-server] Refusing to write outside outDir: ${t}`);return r}async function Lt({routes:e=[],outDir:t,render:n,documentOptions:r={}}={}){let o=[];for(let a of e){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(Ht(a.path)){if(typeof a.getStaticPaths!="function")continue;c=((await a.getStaticPaths()).paths||[]).map(d=>It(a.path,d.params||{}))}for(let u of c){let d=jt(t,u),l=Nt(u,[a]),p={params:l?l.params:{},query:{}},h=n?await n(i,p):await V(i,p,r);if(await $t(d,{recursive:!0}),await $e(fe(d,"index.html"),h),typeof a.loader=="function"){let m=await a.loader(p);await $e(fe(d,"__what_data.json"),N({loaderData:m}))}o.push(u)}}return{pages:o}}function Dt(e={}){return R(e)}async function Mt({outDir:e=".vercel/output",functionName:t="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(e,{recursive:!0});let l={version:3,routes:[{handle:"filesystem"},{src:"/.*",dest:`/${t}`}]};await i(u(e,"config.json"),JSON.stringify(l,null,2)),a&&await c(a,u(e,"static"),{recursive:!0});let f=null;if(r&&typeof r=="object"){f=u(e,"functions",`${t}.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 S=u(f,h);await s(d(S),{recursive:!0}),await i(S,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:e,functionDir:f}}Ut(new Ft);export{_e as ACTION_ENDPOINT,Ze as Form,Ve as action,Mt as buildVercelOutput,j as createActionHandler,ft as createCloudflareHandler,R as createRequestHandler,xt as createServer,Dt as createVercelHandler,ee as csrfMetaTag,wn as definePage,Lt as exportStatic,ot as fetchActionHandler,we as formAction,q as generateCsrfToken,Sn as generateStaticPage,Ye as getRegisteredActions,De as getRevalidationHandler,D as handleActionRequest,be as invalidatePath,nt as nodeActionMiddleware,ze as onRevalidate,V as renderDocument,gn as renderPage,gt as renderToHydratableString,$ as renderToStream,g as renderToString,St as renderToStringAsync,yn as renderToStringWithHead,G as revalidatePath,K as revalidateTag,N as serializeState,bn as server,X as setRevalidationHandler,xe as toNodeListener,Se as useAction,Je as useFormAction,Xe as useMutation,We as useOptimistic,ge as validateCsrfToken,Ot as whatMiddleware};
|
package/node.d.ts
CHANGED
|
@@ -16,7 +16,18 @@ export function toNodeListener(
|
|
|
16
16
|
export function whatMiddleware(options?: RequestHandlerOptions): (req: any, res: any, next?: () => void) => Promise<void>;
|
|
17
17
|
|
|
18
18
|
/** A ready-to-listen node:http server. Starts `scheduler` and stops it on SIGTERM/SIGINT. */
|
|
19
|
-
|
|
19
|
+
// Structural, not `import('node:http').Server`. Referencing a Node builtin here
|
|
20
|
+
// would make @types/node a hard requirement for every consumer of what-server,
|
|
21
|
+
// including the browser and edge ones that never touch this entry point. The
|
|
22
|
+
// runtime value IS an http.Server; this types what callers actually do with it.
|
|
23
|
+
export interface NodeHttpServer {
|
|
24
|
+
listen(...args: any[]): NodeHttpServer;
|
|
25
|
+
close(callback?: (err?: Error) => void): NodeHttpServer;
|
|
26
|
+
address(): string | { address: string; family: string; port: number } | null;
|
|
27
|
+
on(event: string, listener: (...args: any[]) => void): NodeHttpServer;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createServer(options?: RequestHandlerOptions & { scheduler?: { start(): void; stop(): void } }): NodeHttpServer;
|
|
20
31
|
|
|
21
32
|
/** Vercel Functions entry: a Web-Fetch handler. */
|
|
22
33
|
export function createVercelHandler(options?: RequestHandlerOptions): (request: Request) => Promise<Response>;
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "what-server",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.3",
|
|
4
4
|
"description": "What Framework - SSR, islands architecture, static generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"types": "index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"types": "./index.d.ts",
|
|
11
10
|
"node": {
|
|
12
11
|
"types": "./node.d.ts",
|
|
13
12
|
"production": "./dist/node.min.js",
|
|
14
13
|
"import": "./src/node.js",
|
|
15
14
|
"default": "./src/node.js"
|
|
16
15
|
},
|
|
16
|
+
"types": "./index.d.ts",
|
|
17
17
|
"production": "./dist/index.min.js",
|
|
18
18
|
"import": "./src/index.js",
|
|
19
19
|
"default": "./src/index.js"
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"author": "ZVN DEV (https://zvndev.com)",
|
|
52
52
|
"license": "MIT",
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"what-core": "^0.12.
|
|
55
|
-
"what-router": "^0.12.
|
|
54
|
+
"what-core": "^0.12.3",
|
|
55
|
+
"what-router": "^0.12.3"
|
|
56
56
|
},
|
|
57
57
|
"peerDependenciesMeta": {
|
|
58
58
|
"what-router": {
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
import {
|
|
6
6
|
h,
|
|
7
7
|
_isAriaAttr,
|
|
8
|
+
_beginComponentSSR,
|
|
9
|
+
_endComponentSSR,
|
|
10
|
+
_mapArrayToArray,
|
|
8
11
|
getServerContext,
|
|
9
12
|
runWithServerContext,
|
|
10
13
|
beginHeadCollection,
|
|
@@ -71,6 +74,20 @@ function _renderHydratable(vnode) {
|
|
|
71
74
|
return `<!--$-->${_renderHydratable(vnode())}<!--/$-->`;
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
// Compiled keyed list: an inserter taking (parent, marker), not a thunk.
|
|
78
|
+
// Calling it with no arguments threw and SSR swallowed it, so every compiled
|
|
79
|
+
// keyed list server-rendered as an empty container. See _mapArrayToArray.
|
|
80
|
+
if (typeof vnode === 'function' && vnode._mapArray) {
|
|
81
|
+
try {
|
|
82
|
+
return `<!--$-->${_renderHydratable(_mapArrayToArray(vnode))}<!--/$-->`;
|
|
83
|
+
} catch (e) {
|
|
84
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
|
|
85
|
+
console.warn('[what-server] Error rendering keyed list in SSR:', e.message);
|
|
86
|
+
}
|
|
87
|
+
return '<!--$--><!--/$-->';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
74
91
|
// Reactive function child — wrap in dynamic content markers
|
|
75
92
|
if (typeof vnode === 'function') {
|
|
76
93
|
try {
|
|
@@ -91,8 +108,13 @@ function _renderHydratable(vnode) {
|
|
|
91
108
|
// Component — add hydration key to root element
|
|
92
109
|
if (typeof vnode.tag === 'function') {
|
|
93
110
|
const hkId = nextHydrationId();
|
|
94
|
-
const
|
|
95
|
-
|
|
111
|
+
const ctx = _beginComponentSSR(vnode.tag);
|
|
112
|
+
let html;
|
|
113
|
+
try {
|
|
114
|
+
html = _renderHydratable(vnode.tag({ ...vnode.props, children: vnode.children }));
|
|
115
|
+
} finally {
|
|
116
|
+
_endComponentSSR(ctx);
|
|
117
|
+
}
|
|
96
118
|
// Inject data-hk into the first element tag if present
|
|
97
119
|
return injectHydrationKey(html, hkId);
|
|
98
120
|
}
|
|
@@ -146,6 +168,18 @@ export function renderToString(vnode) {
|
|
|
146
168
|
return renderToString(vnode());
|
|
147
169
|
}
|
|
148
170
|
|
|
171
|
+
// Compiled keyed list: see _renderHydratable above.
|
|
172
|
+
if (typeof vnode === 'function' && vnode._mapArray) {
|
|
173
|
+
try {
|
|
174
|
+
return renderToString(_mapArrayToArray(vnode));
|
|
175
|
+
} catch (e) {
|
|
176
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
|
|
177
|
+
console.warn('[what-server] Error rendering keyed list in SSR:', e.message);
|
|
178
|
+
}
|
|
179
|
+
return '';
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
149
183
|
// Reactive function child — call to get value
|
|
150
184
|
if (typeof vnode === 'function') {
|
|
151
185
|
try {
|
|
@@ -178,9 +212,18 @@ export function renderToString(vnode) {
|
|
|
178
212
|
}
|
|
179
213
|
|
|
180
214
|
// Component
|
|
215
|
+
//
|
|
216
|
+
// Run it under a component context. Calling it bare left the component stack
|
|
217
|
+
// empty, so every context-dependent hook threw and the render failed outright
|
|
218
|
+
// rather than degrading. The context has to stay on the stack while the
|
|
219
|
+
// result is rendered, because useContext resolves by walking parent contexts.
|
|
181
220
|
if (typeof vnode.tag === 'function') {
|
|
182
|
-
const
|
|
183
|
-
|
|
221
|
+
const ctx = _beginComponentSSR(vnode.tag);
|
|
222
|
+
try {
|
|
223
|
+
return renderToString(vnode.tag({ ...vnode.props, children: vnode.children }));
|
|
224
|
+
} finally {
|
|
225
|
+
_endComponentSSR(ctx);
|
|
226
|
+
}
|
|
184
227
|
}
|
|
185
228
|
|
|
186
229
|
// Element
|
|
@@ -315,6 +358,20 @@ export async function* renderToStream(vnode, ctx) {
|
|
|
315
358
|
return;
|
|
316
359
|
}
|
|
317
360
|
|
|
361
|
+
// Compiled keyed list: see _renderHydratable above.
|
|
362
|
+
if (typeof vnode === 'function' && vnode._mapArray) {
|
|
363
|
+
let rows = null;
|
|
364
|
+
try {
|
|
365
|
+
rows = runWithServerContext(ctx, () => _mapArrayToArray(vnode));
|
|
366
|
+
} catch (e) {
|
|
367
|
+
if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
|
|
368
|
+
console.warn('[what-server] Error rendering keyed list in stream SSR:', e.message);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (rows) yield* renderToStream(rows, ctx);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
318
375
|
// Reactive function child — call to get value
|
|
319
376
|
if (typeof vnode === 'function') {
|
|
320
377
|
try {
|
|
@@ -361,6 +418,10 @@ export async function* renderToStream(vnode, ctx) {
|
|
|
361
418
|
}
|
|
362
419
|
|
|
363
420
|
if (typeof vnode.tag === 'function') {
|
|
421
|
+
// The frame stays open across the yields below: useContext resolves by
|
|
422
|
+
// walking parent contexts, so a Provider's context has to outlive the
|
|
423
|
+
// streaming of its own subtree.
|
|
424
|
+
const componentCtx = _beginComponentSSR(vnode.tag);
|
|
364
425
|
try {
|
|
365
426
|
const result = runWithServerContext(
|
|
366
427
|
ctx,
|
|
@@ -376,6 +437,8 @@ export async function* renderToStream(vnode, ctx) {
|
|
|
376
437
|
yield _isDevMode
|
|
377
438
|
? `<!-- SSR Error: ${escapeHtml(e.message || 'Component error')} -->`
|
|
378
439
|
: `<!-- SSR Error -->`;
|
|
440
|
+
} finally {
|
|
441
|
+
_endComponentSSR(componentCtx);
|
|
379
442
|
}
|
|
380
443
|
return;
|
|
381
444
|
}
|
package/src/islands.js
CHANGED
|
@@ -473,54 +473,180 @@ export function enhance(selector, handler) {
|
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
475
|
|
|
476
|
-
|
|
476
|
+
/**
|
|
477
|
+
* Recover the double-submit CSRF token for a form.
|
|
478
|
+
*
|
|
479
|
+
* The meta tag alone is not enough. A cached page (mode 'static' or 'hybrid') is
|
|
480
|
+
* shared between visitors, so the adapter deliberately does NOT embed a
|
|
481
|
+
* per-visitor token in it; the token lives only in the cookie. A form inside
|
|
482
|
+
* such a page therefore has no meta tag to read, and blocking on that alone
|
|
483
|
+
* refused perfectly valid submissions. `<Form>` also emits the token as a hidden
|
|
484
|
+
* field, which is the same value, so all three sources are checked.
|
|
485
|
+
*/
|
|
486
|
+
function readFormCsrfToken(form) {
|
|
487
|
+
const meta = document.querySelector('meta[name="csrf-token"]')
|
|
488
|
+
|| document.querySelector('meta[name="what-csrf-token"]');
|
|
489
|
+
if (meta) return meta.getAttribute('content');
|
|
490
|
+
|
|
491
|
+
const field = form.querySelector('input[name="what-csrf-token"], input[name="_csrf"]');
|
|
492
|
+
if (field && field.value) return field.value;
|
|
493
|
+
|
|
494
|
+
const cookie = document.cookie.match(/(?:^|;\s*)what-csrf=([^;]+)/);
|
|
495
|
+
return cookie ? decodeURIComponent(cookie[1]) : null;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Serialize a form the way the browser would, so an enhanced submit and a plain
|
|
500
|
+
* one are indistinguishable to the server.
|
|
501
|
+
*
|
|
502
|
+
* Two details that look pedantic and are not:
|
|
503
|
+
* - newlines in every text entry normalize to CRLF. The urlencoded and
|
|
504
|
+
* multipart serializers both do this per spec; URLSearchParams does not, so
|
|
505
|
+
* a <textarea> round-tripped different bytes with JS on than with JS off.
|
|
506
|
+
* - a File under a non-multipart encoding contributes only its NAME, which is
|
|
507
|
+
* what a native submit sends. Sending "[object File]" would be worse than
|
|
508
|
+
* useless, and silently sending nothing hides a real mistake.
|
|
509
|
+
*/
|
|
510
|
+
function formEntries(form, submitter, multipart) {
|
|
511
|
+
const data = new FormData(form);
|
|
512
|
+
|
|
513
|
+
// FormData(form) never includes the submit button, so a multi-button form
|
|
514
|
+
// could not tell the server which button was pressed. Native submits include
|
|
515
|
+
// the submitter's name/value.
|
|
516
|
+
if (submitter && submitter.name) {
|
|
517
|
+
data.append(submitter.name, submitter.value ?? '');
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (multipart) return data;
|
|
521
|
+
|
|
522
|
+
const params = new URLSearchParams();
|
|
523
|
+
let droppedFile = null;
|
|
524
|
+
for (const [key, value] of data) {
|
|
525
|
+
if (typeof value === 'string') {
|
|
526
|
+
params.append(key, value.replace(/\r\n|\r|\n/g, '\r\n'));
|
|
527
|
+
} else {
|
|
528
|
+
droppedFile = droppedFile || key;
|
|
529
|
+
params.append(key, value.name ?? '');
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (droppedFile && typeof console !== 'undefined') {
|
|
534
|
+
console.warn(
|
|
535
|
+
`[what] Form field "${droppedFile}" holds a file, but the form is not ` +
|
|
536
|
+
'enctype="multipart/form-data", so only the file NAME is sent. This is what ' +
|
|
537
|
+
'a plain HTML submit does too. Add enctype="multipart/form-data" to upload ' +
|
|
538
|
+
'the bytes.'
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
return params;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Form enhancement: submit via fetch instead of a full page load.
|
|
546
|
+
*
|
|
547
|
+
* The encoding is not a detail. `/__what_action` parses
|
|
548
|
+
* application/x-www-form-urlencoded or JSON, never multipart, so an enhanced
|
|
549
|
+
* submit of a default form has to use the same encoding as the plain HTML submit
|
|
550
|
+
* it replaces. Posting a FormData object unconditionally produced a multipart
|
|
551
|
+
* body the endpoint could not parse: the action id went missing and every
|
|
552
|
+
* enhanced `<Form>` failed with 400 while the no-JS path kept working.
|
|
553
|
+
*
|
|
554
|
+
* The encoding now follows the form's own `enctype`, exactly as the browser
|
|
555
|
+
* would, so a form that declares multipart still uploads its files.
|
|
556
|
+
*
|
|
557
|
+
* On success the action endpoint answers 303 to the form's `_redirect` target,
|
|
558
|
+
* which fetch follows. The page is then navigated there so the enhanced path
|
|
559
|
+
* lands where the unenhanced one would. Cancel the `form:response` event to keep
|
|
560
|
+
* the page put and handle the response yourself.
|
|
561
|
+
*/
|
|
477
562
|
export function enhanceForms(selector = 'form[data-enhance]') {
|
|
478
563
|
enhance(selector, (form) => {
|
|
479
|
-
form.addEventListener('submit', async (
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const formData = new FormData(form);
|
|
483
|
-
const method = form.method.toUpperCase() || 'POST';
|
|
484
|
-
const action = form.action || location.href;
|
|
564
|
+
form.addEventListener('submit', async (event) => {
|
|
565
|
+
event.preventDefault();
|
|
485
566
|
|
|
486
567
|
try {
|
|
487
|
-
//
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
//
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
568
|
+
// getAttribute, never the properties. HTMLFormElement is
|
|
569
|
+
// [LegacyOverrideBuiltIns]: a field named "method" or "action" SHADOWS
|
|
570
|
+
// form.method / form.action with the input element itself. Reading
|
|
571
|
+
// `form.method.toUpperCase()` then threw a TypeError after
|
|
572
|
+
// preventDefault() had already run, so the submit produced no fetch, no
|
|
573
|
+
// form:error, and no native fallback. It just did nothing.
|
|
574
|
+
const submitter = event.submitter || null;
|
|
575
|
+
const attr = (name) => (submitter && submitter.getAttribute(`form${name}`))
|
|
576
|
+
|| form.getAttribute(name);
|
|
577
|
+
|
|
578
|
+
const method = (attr('method') || 'get').toUpperCase();
|
|
579
|
+
const action = new URL(attr('action') || location.href, location.href);
|
|
580
|
+
const enctype = (attr('enctype') || '').toLowerCase();
|
|
581
|
+
const multipart = enctype === 'multipart/form-data';
|
|
582
|
+
|
|
583
|
+
const entries = formEntries(form, submitter, multipart);
|
|
584
|
+
|
|
585
|
+
// CSRF is about protecting OUR endpoint. A form aimed at another origin
|
|
586
|
+
// must neither be blocked by our token policy nor be handed our token:
|
|
587
|
+
// attaching it would export the visitor's double-submit secret to a
|
|
588
|
+
// third party.
|
|
589
|
+
const sameOrigin = action.origin === location.origin;
|
|
590
|
+
const headers = { 'X-Requested-With': 'XMLHttpRequest' };
|
|
591
|
+
|
|
592
|
+
if (sameOrigin) {
|
|
593
|
+
const csrfToken = readFormCsrfToken(form);
|
|
594
|
+
const noCsrf = form.getAttribute('data-no-csrf') === 'true';
|
|
595
|
+
if (!csrfToken && !noCsrf) {
|
|
596
|
+
console.warn(
|
|
597
|
+
'[what] Form submission blocked: no CSRF token found. ' +
|
|
598
|
+
'Add a <meta name="what-csrf-token"> tag (csrfMetaTag() emits it) ' +
|
|
599
|
+
'or set data-no-csrf="true" on the form to opt out.'
|
|
600
|
+
);
|
|
601
|
+
form.dispatchEvent(new CustomEvent('form:error', {
|
|
602
|
+
bubbles: true,
|
|
603
|
+
detail: { error: new Error('Missing CSRF token') },
|
|
604
|
+
}));
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
if (csrfToken) headers['X-CSRF-Token'] = csrfToken;
|
|
505
608
|
}
|
|
506
609
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
610
|
+
let body;
|
|
611
|
+
if (method === 'GET') {
|
|
612
|
+
// A native GET submit REPLACES the query string with the form data.
|
|
613
|
+
// The previous code built the params and then threw them away, so an
|
|
614
|
+
// enhanced GET form fetched a bare URL with none of its fields.
|
|
615
|
+
action.search = String(entries);
|
|
616
|
+
} else if (multipart) {
|
|
617
|
+
// Hand FormData straight to fetch so the browser writes the boundary.
|
|
618
|
+
body = entries;
|
|
619
|
+
} else {
|
|
620
|
+
body = entries;
|
|
621
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
512
622
|
}
|
|
513
623
|
|
|
514
|
-
const response = await fetch(action, {
|
|
624
|
+
const response = await fetch(action.href, {
|
|
515
625
|
method,
|
|
516
|
-
body
|
|
626
|
+
body,
|
|
517
627
|
headers,
|
|
628
|
+
credentials: 'same-origin',
|
|
518
629
|
});
|
|
519
630
|
|
|
520
|
-
|
|
631
|
+
const responseEvent = new CustomEvent('form:response', {
|
|
521
632
|
bubbles: true,
|
|
522
|
-
|
|
523
|
-
|
|
633
|
+
cancelable: true,
|
|
634
|
+
detail: { response, ok: response.ok, redirected: response.redirected },
|
|
635
|
+
});
|
|
636
|
+
const proceed = form.dispatchEvent(responseEvent);
|
|
637
|
+
|
|
638
|
+
// Same-origin only. A native submit would follow an off-site redirect,
|
|
639
|
+
// but a framework default that can navigate the page to another origin
|
|
640
|
+
// on a server's say-so is not a default worth having. Listen for
|
|
641
|
+
// form:response if you need that.
|
|
642
|
+
if (proceed && response.ok && response.redirected) {
|
|
643
|
+
let target = null;
|
|
644
|
+
try {
|
|
645
|
+
const url = new URL(response.url, location.href);
|
|
646
|
+
if (url.origin === location.origin) target = url.href;
|
|
647
|
+
} catch { /* unparseable: do not navigate */ }
|
|
648
|
+
if (target) location.assign(target);
|
|
649
|
+
}
|
|
524
650
|
} catch (error) {
|
|
525
651
|
form.dispatchEvent(new CustomEvent('form:error', {
|
|
526
652
|
bubbles: true,
|