@finesoft/front 0.5.1 → 0.5.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.
Files changed (128) hide show
  1. package/README.md +4 -4
  2. package/dist/Outlet.svelte +39 -0
  3. package/dist/Outlet.svelte.d.ts +7 -0
  4. package/dist/browser-CR5vhgXg.mjs +1317 -0
  5. package/dist/browser-kFMjlLGT.d.mts +262 -0
  6. package/dist/browser.d.mts +7 -2
  7. package/dist/browser.mjs +9 -1
  8. package/dist/controller-types-CgmJ6-le.d.mts +16 -0
  9. package/dist/cookies-BiRlUanX.d.mts +786 -0
  10. package/dist/fetch-policy-BHT8RtrL.mjs +82 -0
  11. package/dist/host-guard-DDWxLpFL.mjs +222 -0
  12. package/dist/http-B6CJqDyf.d.mts +46 -0
  13. package/dist/http-CaxrMD1A.d.mts +1 -0
  14. package/dist/http-D70PL72H.mjs +257 -0
  15. package/dist/http.d.mts +3 -0
  16. package/dist/http.mjs +2 -0
  17. package/dist/index-node.d.mts +15 -0
  18. package/dist/index-node.mjs +15 -0
  19. package/dist/index.d.mts +48 -697
  20. package/dist/index.mjs +44 -261
  21. package/dist/load-node.d.mts +5 -0
  22. package/dist/load-node.mjs +10 -0
  23. package/dist/load-portable.d.mts +5 -0
  24. package/dist/load-portable.mjs +8 -0
  25. package/dist/lru-map-BKoUAySU.mjs +50 -0
  26. package/dist/messages-CAt2QdGr.mjs +140 -0
  27. package/dist/native-contract-DuR25hYB.d.mts +14 -0
  28. package/dist/native-contract.d.mts +2 -0
  29. package/dist/native-contract.mjs +1 -0
  30. package/dist/node-D9hB4dsz.d.mts +35 -0
  31. package/dist/node.d.mts +2 -0
  32. package/dist/node.mjs +59 -0
  33. package/dist/path-CGFl2w7D.mjs +113 -0
  34. package/dist/path-CXT6xGPO.d.mts +261 -0
  35. package/dist/portable-CaxrMD1A.d.mts +1 -0
  36. package/dist/portable.d.mts +11 -0
  37. package/dist/portable.mjs +12 -0
  38. package/dist/proxy-2dSWO-Xw.d.mts +53 -0
  39. package/dist/proxy-z02VvGIj.mjs +7520 -0
  40. package/dist/public-types-BcJM-AYc.mjs +835 -0
  41. package/dist/react-DhwBRw01.d.mts +16 -0
  42. package/dist/react.d.mts +3 -0
  43. package/dist/react.mjs +29 -0
  44. package/dist/rolldown-runtime-B4iAMlE-.mjs +35 -0
  45. package/dist/secure-fetch-Xlht2jd7.d.mts +30 -0
  46. package/dist/server-controller-proxy-BkVuVWVD.d.mts +38 -0
  47. package/dist/session-DnB4ZC3x.d.mts +1279 -0
  48. package/dist/src-BQBfaaPO.mjs +3825 -0
  49. package/dist/src-Ftl_0rhu.mjs +28 -0
  50. package/dist/ssr-BLzYP4wU.d.mts +207 -0
  51. package/dist/ssr-Tn4YkuxM.mjs +357 -0
  52. package/dist/ssr.d.mts +3 -0
  53. package/dist/ssr.mjs +3 -0
  54. package/dist/svelte-Dr5to3SE.d.mts +16 -0
  55. package/dist/svelte.d.mts +3 -0
  56. package/dist/svelte.mjs +13 -0
  57. package/dist/typegen-C-WeJCtf.d.mts +12 -0
  58. package/dist/typegen-cli.d.mts +1 -0
  59. package/dist/typegen-cli.mjs +11 -0
  60. package/dist/typegen.d.mts +3 -0
  61. package/dist/typegen.mjs +2 -0
  62. package/dist/types-B1BT0N3t.mjs +402 -0
  63. package/dist/undici-CPfL25Hr.mjs +22262 -0
  64. package/dist/vite-Cj4SPA8D.d.mts +277 -0
  65. package/dist/vite.d.mts +4 -0
  66. package/dist/vite.mjs +2354 -0
  67. package/dist/vue-DGmzuKho.d.mts +32 -0
  68. package/dist/vue.d.mts +3 -0
  69. package/dist/vue.mjs +56 -0
  70. package/dist/web.d.mts +6 -0
  71. package/dist/web.mjs +8 -0
  72. package/dist/worker.d.mts +2 -0
  73. package/dist/worker.mjs +2 -0
  74. package/docs/01-getting-started.md +67 -199
  75. package/docs/02-routing-and-controllers.md +163 -241
  76. package/docs/03-middleware.md +10 -212
  77. package/docs/04-rendering-and-hydration.md +7 -332
  78. package/docs/05-i18n.md +7 -237
  79. package/docs/06-http-client.md +20 -263
  80. package/docs/07-di-container.md +23 -257
  81. package/docs/08-observability.md +6 -286
  82. package/docs/09-server-and-deployment.md +59 -219
  83. package/docs/10-features-platform-pwa.md +7 -231
  84. package/docs/11-navigation.md +143 -288
  85. package/docs/12-session-restoration.md +6 -214
  86. package/docs/README.md +7 -7
  87. package/docs/advanced/custom-action-handler.md +29 -229
  88. package/docs/advanced/custom-adapter.md +7 -259
  89. package/docs/advanced/custom-event-recorder.md +7 -312
  90. package/docs/advanced/inline-proxy-codegen.md +6 -185
  91. package/docs/advanced/multi-tenant-scopes.md +10 -323
  92. package/docs/engineering/ci-release-flow.md +35 -222
  93. package/docs/engineering/project-structure.md +34 -277
  94. package/docs/engineering/testing.md +8 -310
  95. package/docs/pitfalls/container-scope-leak.md +2 -214
  96. package/docs/pitfalls/i18n-bundle-size.md +6 -176
  97. package/docs/pitfalls/proxy-binary-payloads.md +8 -12
  98. package/docs/pitfalls/ssr-hydration-mismatch.md +9 -155
  99. package/docs/pitfalls/ssr-vs-csr-globals.md +9 -170
  100. package/docs/zh/01-getting-started.md +67 -199
  101. package/docs/zh/02-routing-and-controllers.md +166 -244
  102. package/docs/zh/03-middleware.md +10 -212
  103. package/docs/zh/04-rendering-and-hydration.md +7 -332
  104. package/docs/zh/05-i18n.md +7 -237
  105. package/docs/zh/06-http-client.md +20 -263
  106. package/docs/zh/07-di-container.md +23 -257
  107. package/docs/zh/08-observability.md +6 -283
  108. package/docs/zh/09-server-and-deployment.md +59 -219
  109. package/docs/zh/10-features-platform-pwa.md +7 -231
  110. package/docs/zh/11-navigation.md +130 -290
  111. package/docs/zh/12-session-restoration.md +6 -214
  112. package/docs/zh/README.md +4 -4
  113. package/docs/zh/advanced/custom-action-handler.md +29 -229
  114. package/docs/zh/advanced/custom-adapter.md +7 -259
  115. package/docs/zh/advanced/custom-event-recorder.md +7 -312
  116. package/docs/zh/advanced/inline-proxy-codegen.md +6 -185
  117. package/docs/zh/advanced/multi-tenant-scopes.md +10 -323
  118. package/docs/zh/engineering/ci-release-flow.md +35 -222
  119. package/docs/zh/engineering/project-structure.md +34 -277
  120. package/docs/zh/engineering/testing.md +8 -310
  121. package/docs/zh/pitfalls/container-scope-leak.md +2 -214
  122. package/docs/zh/pitfalls/i18n-bundle-size.md +6 -176
  123. package/docs/zh/pitfalls/proxy-binary-payloads.md +8 -12
  124. package/docs/zh/pitfalls/ssr-hydration-mismatch.md +9 -155
  125. package/docs/zh/pitfalls/ssr-vs-csr-globals.md +9 -170
  126. package/package.json +118 -20
  127. package/dist/browser-BHhVWXik.mjs +0 -2
  128. package/dist/browser-BV2BBXm7.d.mts +0 -2811
package/dist/index.mjs CHANGED
@@ -1,264 +1,47 @@
1
- import{$ as e,$t as t,A as n,An as r,At as i,B as a,Bn as o,Bt as s,C as c,Cn as l,Ct as u,D as d,Dn as f,Dt as p,E as m,En as h,Et as g,F as _,Fn as v,Ft as y,G as b,Gn as x,Gt as S,H as ee,Hn as C,Ht as w,I as T,In as E,It as te,J as ne,Jn as re,Jt as ie,K as ae,Kn as oe,Kt as se,L as D,Ln as ce,Lt as le,M as ue,Mn as de,Mt as fe,N as pe,Nn as me,Nt as he,O as ge,On as _e,Ot as ve,P as ye,Pn as be,Pt as xe,Q as Se,Qt as Ce,R as we,Rn as Te,Rt as Ee,S as De,Sn as Oe,St as ke,T as Ae,Tn as je,Tt as O,U as k,Un as Me,Ut as Ne,V as Pe,Vn as Fe,Vt as Ie,W as Le,Wn as Re,Wt as A,X as ze,Xn as Be,Xt as Ve,Y as He,Yn as Ue,Yt as We,Z as Ge,Zn as Ke,Zt as qe,_ as Je,_n as Ye,_t as Xe,a as Ze,an as Qe,at as $e,b as et,bn as tt,bt as nt,c as rt,cn as it,ct as j,d as at,dn as ot,dt as st,en as ct,et as lt,f as ut,fn as M,ft as dt,g as ft,gn as pt,gt as mt,h as ht,hn as gt,ht as _t,i as vt,in as yt,it as bt,j as xt,jn as N,jt as St,k as Ct,kn as P,kt as wt,l as Tt,ln as Et,lt as F,m as Dt,mn as Ot,mt as kt,n as At,nn as jt,nt as Mt,o as Nt,on as Pt,ot as Ft,p as It,pn as Lt,pt as Rt,q as zt,qn as Bt,qt as I,r as Vt,rn as Ht,rt as Ut,s as Wt,sn as Gt,st as Kt,t as qt,tn as Jt,tt as L,u as Yt,un as Xt,ut as Zt,v as Qt,vn as $t,vt as en,w as tn,wn as nn,wt as rn,x as an,xn as on,xt as sn,y as cn,yn as ln,yt as un,z as dn,zn as fn,zt as pn}from"./browser-BHhVWXik.mjs";import{Hono as R}from"hono";async function z(e){return mn(e,0)}async function mn(e,t){if(t>=5)throw Error(`[SSR] Rewrite recursion depth exceeded (max 5) at "${e.url}"`);let{url:n,frameworkConfig:r,bootstrap:i,getErrorPage:a,renderApp:o,ssrContext:s,resolveLocale:c,loadMessages:l}=e,u=new URL(n,`http://localhost`),f=u.pathname+u.search,p=c?.(n,s?.request),m=p?{...r,locale:p.lang}:r,h=await P({locale:m.locale,loadMessages:l,context:m.locale?{runtime:`server`,fetch:hn(s?.fetch??m.fetch),url:f,request:s?.request}:void 0}),g={...m,fetch:s?.fetch??m.fetch},_=I.create({...g,_resolvedMessages:h});i(_);try{let n=await _.routeUrl(f);if(n?.renderMode===`csr`)return{html:``,head:``,css:``,serverData:[],renderMode:`csr`};let r,i=[],c;if(n){let l=d({url:f,intent:n.intent,container:_.container,request:s?.request}),u=await _.runBeforeLoad(l,n.beforeGuards);if(u.kind===`rewrite`)return mn({...e,url:u.url},t+1);if(u.kind!==`next`){let e=await gn(u,a,o,_);if(e)return e}try{r=await _.dispatch(n.intent),i=[{intent:n.intent,data:r}]}catch(e){_.container.resolve(M.LOGGER).error(`[SSR] dispatch failed for intent "${n.intent.id}":`,e),r=a(500,`Internal error`)}let p={...l,page:r},m=await _.runAfterLoad(p,n.afterGuards);if(m.kind===`rewrite`)c=m.url;else if(m.kind!==`next`){let e=await gn(m,a,o,_);if(e)return e}}else r=a(404,`Page not found`);let l=await o(r,_),u=p??_.getLocale();return{html:l.html,head:l.head,css:l.css,serverData:i,renderMode:n?.renderMode,slots:l.slots,locale:u,rewriteUrl:c}}finally{_.dispose()}}function hn(e){return(e??globalThis.fetch?.bind(globalThis))||(()=>{throw Error(`[ssrRender] loadMessages requires a fetch implementation.`)})}async function gn(e,t,n,r){switch(e.kind){case`next`:case`rewrite`:return null;case`redirect`:return{html:``,head:``,css:``,serverData:[],redirect:{url:e.url,status:e.status}};case`deny`:{let i=await n(t(e.status,e.message),r);return{html:i.html,head:i.head,css:i.css,serverData:[],slots:i.slots,status:e.status}}}}function _n(e){let{bootstrap:t,getErrorPage:n,renderApp:r,frameworkConfig:i,resolveLocale:a,loadMessages:o}=e;return(e,s)=>z({url:e,frameworkConfig:i??{},bootstrap:t,getErrorPage:n,renderApp:(e,t)=>r(e,t),ssrContext:s,resolveLocale:a,loadMessages:o})}const vn={HEAD:`<!--ssr-head-->`,BODY:`<!--ssr-body-->`,DATA:`<!--ssr-data-->`},yn=/<!--ssr-([a-z][a-z0-9-]*)-->/g;function B(e){let{template:t,head:n,css:r,html:i,serializedData:a,slots:o,locale:s}=e,c={head:`${n}\n${r?`<style>${r}</style>`:``}`,body:i,data:`<script id="serialized-server-data" type="application/json">${a}<\/script>`,...o},l=t.replace(yn,(e,t)=>c[t]??``);return s&&(l=Sn(l,s)),l}function V(e,t){let n=e.replace(yn,()=>``);return t&&(n=Sn(n,t)),n}const bn=/\s+lang=("[^"]*"|'[^']*'|[^\s>]+)/gi,xn=/\s+dir=("[^"]*"|'[^']*'|[^\s>]+)/gi;function Sn(e,t){return e.replace(/(<html)([^>]*)(>)/i,(e,n,r,i)=>`${n}${r.replace(bn,``).replace(xn,``)} lang="${t.lang}" dir="${t.dir}"${i}`)}const Cn=`@finesoft/navigation-tree`;async function wn(e){let{url:t,frameworkConfig:n,bootstrap:r,getErrorPage:a,renderApp:o,navigation:s,ssrContext:c,resolveLocale:l,loadMessages:u}=e,d=new URL(t,`http://localhost`),f=d.pathname+d.search,p=l?.(t,c?.request),m=p?{...n,locale:p.lang}:n,h=await P({locale:m.locale,loadMessages:u,context:m.locale?{runtime:`server`,fetch:In(c?.fetch??m.fetch),url:f,request:c?.request}:void 0}),g={...m,fetch:c?.fetch??m.fetch},_=I.create({...g,_resolvedMessages:h});r(_);try{let e=await Tn(_,s,f);if(e===void 0)return Fn({framework:_,resolvedLocale:p,renderApp:o,page:a(404,`Page not found`),snapshot:{tree:i(`@finesoft/not-found`),destinations:[]},serverData:[],renderMode:void 0,status:void 0});let{tree:t,renderMode:n}=e;if(n===`csr`)return{html:``,head:``,css:``,serverData:[],renderMode:`csr`,snapshot:{tree:t,destinations:[]}};let r,l=await En({framework:_,navigation:s,initialTree:t,fullPath:f,request:c?.request,getErrorPage:a,onRedirect:e=>{r??=e}}).resolve();if(r!==void 0)return{html:``,head:``,css:``,serverData:[],redirect:r,snapshot:l};let u=Dn(l,a);return Fn({framework:_,resolvedLocale:p,renderApp:o,page:u.page,snapshot:l,serverData:An(l),renderMode:n,status:u.status})}finally{_.dispose()}}async function Tn(e,t,n){let r=t.codec.decode(n,e.router);if(r!==void 0)return{tree:r,renderMode:void 0};let a=t.initial?.(n);if(a!==void 0)return{tree:a,renderMode:void 0};let o=await e.routeUrl(n);if(o!==null)return{tree:i(o.intent.id,o.intent.params??{}),renderMode:o.renderMode}}function En(e){let{framework:t,navigation:n,initialTree:r,fullPath:i,request:a,getErrorPage:o,onRedirect:s}=e;return L({intentDispatcher:t.intentDispatcher,router:t.router,initial:r,beforeLoad:n.beforeLoad,afterLoad:n.afterLoad,getErrorPage:o,onRedirect:s,createContext:({intent:e,params:n})=>({container:t.container,url:i,navigation:d({url:i,intent:{id:e,params:n},container:t.container,request:a})})})}function Dn(e,t){let n=On(e.tree);if(n!==void 0){let t=e.destinations.find(e=>e.intent===n.intent&&kn(e.params,n.params));if(t!==void 0)return t}return e.destinations.length>0?e.destinations[0]:{intent:`@finesoft/empty`,params:{},page:t(404,`Page not found`),status:404}}function On(e){let t=e;for(;;)switch(t.kind){case`leaf`:return{intent:t.intent,params:t.params};case`stack`:if(t.entries.length===0)return;t=t.entries[t.entries.length-1];break;case`tabs`:{let e=t.branches[t.active];if(e===void 0)return;t=e;break}case`split`:{let e;for(let n of t.columns)n.content!==void 0&&(e=n.content);if(e===void 0)return;t=e;break}}}function kn(e,t){let n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(let r of n)if(e[r]!==t[r])return!1;return!0}function An(e){let t=[];for(let n of e.destinations)t.push({intent:{id:n.intent,params:n.params},data:n.page});return t.push(jn(e.tree)),t}function jn(e){let t={__finesoftNavigationTree:!0,tree:F(e)};return{intent:{id:Cn},data:se(t,!0)}}function Mn(e){for(let t of e)if(Pn(t))return j(t.data.tree)}function Nn(e){return e.filter(e=>!Pn(e))}function Pn(e){if(e.intent.id!==`@finesoft/navigation-tree`)return!1;let t=e.data;return typeof t==`object`&&!!t&&t.__finesoftNavigationTree===!0}async function Fn(e){let{framework:t,resolvedLocale:n,renderApp:r,page:i,snapshot:a,serverData:o,renderMode:s,status:c}=e,l=await r(i,t,a),u=n??t.getLocale();return{html:l.html,head:l.head,css:l.css,serverData:o,renderMode:s,slots:l.slots,locale:u,status:c,snapshot:a}}function In(e){return(e??globalThis.fetch?.bind(globalThis))||(()=>{throw Error(`[ssrRenderNavigation] loadMessages requires a fetch implementation.`)})}function Ln(e){let{bootstrap:t,getErrorPage:n,renderApp:r,navigation:i,frameworkConfig:a,resolveLocale:o,loadMessages:s}=e;return(e,c)=>wn({url:e,frameworkConfig:a??{},bootstrap:t,getErrorPage:n,renderApp:r,navigation:i,ssrContext:c,resolveLocale:o,loadMessages:s})}const Rn={"<":`\\u003C`,">":`\\u003E`,"/":`\\u002F`,"\u2028":`\\u2028`,"\u2029":`\\u2029`},zn=RegExp(`[<>/\\u2028\\u2029]`,`g`);let Bn=!1;function Vn(e,t={}){let n=t.onUnmarkedPage??`all`,r=e.map(e=>Hn(e,n));return JSON.stringify(r).replace(zn,e=>Rn[e]??e)}function Hn(e,t){let n=e.data,r=A(n);if(r===!0)return e;if(Array.isArray(r))return{...e,data:Un(n,r)};if(t===`strict`)throw Error(`[serializeServerData] page for intent "${e.intent.id}" has no markPublic marker; wrap it with markPublic(page, ["field", ...]) to declare client-visible fields.`);return t===`base-fields`?{...e,data:Un(n,w)}:(Wn(e.intent.id),e)}function Un(e,t){let n={};for(let r of t)r in e&&(n[r]=e[r]);return n}function Wn(e){Bn||(Bn=!0,Gn()&&console.warn(`[finesoft/ssr] Page for intent "${e}" was serialized without markPublic(); all fields (including any sensitive data) are exposed in the SSR HTML. Wrap your page with markPublic(page, ["field", ...]) to declare client-visible fields explicitly. The next major version will default to BasePage-only fields when no marker is present.`))}function Gn(){try{return globalThis.process?.env?.NODE_ENV!==`production`}catch{return!1}}function Kn(e){return Object.entries(e).map(([e,t])=>t===``?e:`${e}="${qn(t)}"`).join(` `)}function qn(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`).replace(/</g,`&lt;`)}async function Jn(e,t){let n=[];for(let r of e.destinations){let e=k(r.intent,r.params),i=await t({intent:r.intent,params:r.params,entryKey:e,page:r.page}),a=Kn(O(r.intent,e));n.push(`<div ${a}>${i}</div>`)}return n.join(``)}const Yn=new Map,Xn=e=>import(e),Zn=typeof process<`u`&&process.env?.FINESOFT_DEBUG===`1`;function Qn(e){Zn&&console.debug(`[finesoft:dynamic-import] ${e}`)}async function H(e){let t=!e.startsWith(`file:`)&&!e.startsWith(`/`);if(t){let t=Yn.get(e);if(t)return Qn(`cache hit → ${e}`),t}Qn(`importing → ${e}`);let n=await Xn(e);return t&&Yn.set(e,n),n}const U=10*1024*1024;function $n(e){if(e.length>2048)return null;try{if(decodeURIComponent(e)!==e)return null}catch{return null}return e.startsWith(`//`)||!/^[/\w.\-~%:@!$&'()*+,;=]*$/.test(e)?null:e.startsWith(`/`)?e:`/${e}`}function er(e){if(!e.prefix.startsWith(`/`))throw Error(`[proxy] prefix must start with "/": "${e.prefix}"`);let t=e.target.startsWith(`https://`),n=e.target.startsWith(`http://`);if(!t&&!n)throw Error(`[proxy] target must start with "https://" or "http://": "${e.target}"`);n&&console.warn(`[proxy] ⚠ target "${e.target}" uses plain HTTP — traffic will not be encrypted. Use HTTPS in production to prevent data interception.`)}function W(e,t){for(let n of t){er(n);let t=n.methods??[`all`],r=`${n.prefix}/*`,i=async e=>{let t=$n(e.req.path.replace(n.prefix,``));if(!t)return e.text(`Invalid path`,400);let r=new URL(t,n.target),i=new URL(n.target).origin;if(r.origin!==i)return e.text(`Invalid proxy target`,400);new URL(e.req.url).searchParams.forEach((e,t)=>r.searchParams.set(t,e));let a={...n.headers};if(n.auth){let e=process.env[n.auth.envKey];e?a.Authorization=n.auth.type===`bearer`?`Bearer ${e}`:`Basic ${e}`:console.warn(`[Proxy ${n.prefix}] Auth env var "${n.auth.envKey}" is not set`)}try{let t=await fetch(r.toString(),{headers:a,redirect:n.followRedirects?`follow`:`manual`}),i=t.headers.get(`Content-Length`);if(i&&parseInt(i,10)>U)return e.text(`Proxy response too large`,502);let o=await t.arrayBuffer();if(o.byteLength>U)return e.text(`Proxy response too large`,502);let s={"Content-Type":t.headers.get(`Content-Type`)??`application/json`};return n.cache&&(s[`Cache-Control`]=n.cache),e.newResponse(o,t.status,s)}catch(t){return console.error(`[Proxy ${n.prefix}]`,t),e.json({error:`Proxy request failed`},502)}};for(let n of t)e[n](r,i)}}function tr(e){if(!e||e.length===0)return``;for(let t of e)er(t);let t=[];t.push(`
2
- // ─── 框架声明式代理路由 ───
3
- function _sanitizeProxyPath(raw) {
4
- if (raw.length > 2048) return null;
5
- try { if (decodeURIComponent(raw) !== raw) return null; } catch { return null; }
6
- if (raw.startsWith("//")) return null;
7
- if (!/^[/\\w.\\-~%:@!$&'()*+,;=]*$/.test(raw)) return null;
8
- return raw.startsWith("/") ? raw : "/" + raw;
9
- }
10
- `);for(let n of e){let e=n.methods??[`all`],r=`"${n.prefix}/*"`,i=JSON.stringify(n.headers??{}),a=n.cache?JSON.stringify(n.cache):`null`,o=n.followRedirects?`"follow"`:`"manual"`,s=``;n.auth&&(s=`
11
- const _token = (typeof process !== "undefined" && process.env && process.env[${JSON.stringify(n.auth.envKey)}]) || "";
12
- if (_token) _headers.Authorization = "${n.auth.type===`bearer`?`Bearer `:`Basic `}" + _token;`);let c=`async (c) => {
13
- const _sub = _sanitizeProxyPath(c.req.path.replace(${JSON.stringify(n.prefix)}, ""));
14
- if (!_sub) return c.text("Invalid path", 400);
15
- const _target = new URL(_sub, ${JSON.stringify(n.target)});
16
- if (_target.origin !== ${JSON.stringify(new URL(n.target).origin)}) return c.text("Invalid proxy target", 400);
17
- const _reqUrl = new URL(c.req.url);
18
- _reqUrl.searchParams.forEach((v, k) => _target.searchParams.set(k, v));
19
- const _headers = ${i};${s}
20
- try {
21
- const _resp = await fetch(_target.toString(), { headers: _headers, redirect: ${o} });
22
- // Content-Length 快速拒绝,防止 serverless/edge 加载超大响应到内存
23
- const _cl = _resp.headers.get("Content-Length");
24
- if (_cl && parseInt(_cl, 10) > ${U}) {
25
- return c.text("Proxy response too large", 502);
26
- }
27
- // arrayBuffer 保留二进制完整性
28
- const _body = await _resp.arrayBuffer();
29
- if (_body.byteLength > ${U}) {
30
- return c.text("Proxy response too large", 502);
31
- }
32
- const _rh = { "Content-Type": _resp.headers.get("Content-Type") || "application/json" };
33
- if (${a}) _rh["Cache-Control"] = ${a};
34
- return c.newResponse(_body, _resp.status, _rh);
35
- } catch (_e) {
36
- console.error("[Proxy ${n.prefix}]", _e);
37
- return c.json({ error: "Proxy request failed" }, 502);
38
- }
39
- }`;for(let n of e)t.push(`app.${n}(${r}, ${c});`)}return t.join(`
40
- `)}const nr=[`vite`,`esbuild`,`rollup`,`fsevents`,`lightningcss`],rr=[`node:async_hooks`,`node:buffer`,`node:crypto`,`node:fs`,`node:http`,`node:http2`,`node:module`,`node:net`,`node:os`,`node:path`,`node:stream`,`node:url`,`node:util`,`node:zlib`,`crypto`,`http`,`http2`,`stream`];function G(e,t){let n=e.setupPath?`import _setupDefault from "./${e.setupPath}";`:``,r=e.setupPath?`if (typeof _setupDefault === "function") await _setupDefault(app);`:``,i=JSON.stringify(e.renderModes??{}),a=t.platformCache?t.platformCache:`
41
- const ISR_CACHE_MAX = 1000;
42
- const _isrMap = new Map();
43
- async function platformCacheGet(url) {
44
- return _isrMap.get(url) ?? null;
45
- }
46
- async function platformCacheSet(url, html) {
47
- if (_isrMap.size >= ISR_CACHE_MAX) {
48
- const first = _isrMap.keys().next().value;
49
- _isrMap.delete(first);
50
- }
51
- _isrMap.set(url, html);
52
- }`;return`
53
- import { Hono } from "hono";
54
- ${t.platformImport}
55
- import { render, serializeServerData } from "./${e.ssrEntry}";
56
- ${n}
57
-
58
- const TEMPLATE = ${JSON.stringify(e.templateHtml)};
59
- const RENDER_MODES = ${i};
60
- const DEFAULT_LOCALE = ${JSON.stringify(e.defaultLocale??null)};
61
- ${a}
62
-
63
- function injectSSR(t, head, css, html, data, locale) {
64
- const injected = t
65
- .replace(/<!--ssr-([a-z][a-z0-9-]*)-->/g, (_, name) => {
66
- const replacements = {
67
- head: head + "\n<style>" + css + "</style>",
68
- body: html,
69
- data: '<script id="serialized-server-data" type="application/json">' + data + "<\/script>",
70
- };
71
- return replacements[name] ?? "";
72
- });
73
- return applyLocaleToHtml(injected, locale);
74
- }
75
-
76
- function applyLocaleToHtml(html, locale) {
77
- if (!locale) return html;
78
- return html.replace(/<html([^>]*)>/i, (_, attrs) => {
79
- const a = attrs
80
- .replace(/\\s+lang=("[^"]*"|'[^']*'|[^\\s>]+)/gi, "")
81
- .replace(/\\s+dir=("[^"]*"|'[^']*'|[^\\s>]+)/gi, "");
82
- return "<html" + a + ' lang="' + locale.lang + '" dir="' + locale.dir + '">';
83
- });
84
- }
85
-
86
- function getLocaleAttrs(lang) {
87
- if (!lang) return undefined;
88
- const RTL = new Set(["ar","arc","dv","fa","ha","he","khw","ks","ku","ps","ur","yi"]);
89
- const base = lang.split(/[-_]/)[0].toLowerCase();
90
- return { lang: lang, dir: RTL.has(base) ? "rtl" : "ltr" };
91
- }
92
-
93
- function injectCSRShell(t, locale) {
94
- const stripped = t.replace(/<!--ssr-([a-z][a-z0-9-]*)-->/g, () => "");
95
- return applyLocaleToHtml(stripped, locale);
96
- }
97
-
98
- function matchRenderMode(url) {
99
- const path = url.split("?")[0];
100
- if (RENDER_MODES[path]) return RENDER_MODES[path];
101
- for (const [pattern, mode] of Object.entries(RENDER_MODES)) {
102
- if (pattern.includes("*")) {
103
- const escaped = pattern.replace(/[.+?^\${}()|[\\]\\\\]/g, "\\\\$&");
104
- const re = new RegExp("^" + escaped.replace(/\\*/g, ".*") + "$");
105
- if (re.test(path)) return mode;
106
- }
107
- }
108
- return null;
109
- }
110
-
111
- const app = new Hono();
112
- ${tr(e.proxies??[])}
113
- ${r}
114
- ${t.platformMiddleware??``}
115
-
116
- // 内部 fetch 回环:SSR 控制器的 fetch 请求直接走 Hono 内存路由
117
- // 深度通过请求头传递,并发安全且能跨渲染正确追踪递归
118
- const _SSR_DEPTH_HEADER = "x-ssr-depth";
119
- const _MAX_SSR_DEPTH = 5;
120
-
121
- function _createInternalFetch(depth) {
122
- return function(input, init) {
123
- if (typeof input === "string" && input.startsWith("/")) {
124
- const req = new Request("http://localhost" + input, init);
125
- req.headers.set(_SSR_DEPTH_HEADER, String(depth));
126
- return app.fetch(req);
127
- }
128
- return globalThis.fetch(input, init);
129
- };
130
- }
131
-
132
- app.get("*", async (c) => {
133
- // 递归深度保护:从请求头读取 SSR 深度
134
- const _ssrDepth = parseInt(c.req.header(_SSR_DEPTH_HEADER) || "0", 10);
135
- if (_ssrDepth >= _MAX_SSR_DEPTH) {
136
- return c.text("SSR recursion loop detected", 508);
137
- }
138
-
139
- const url = c.req.path + (c.req.url.includes("?") ? "?" + c.req.url.split("?")[1] : "");
140
- try {
141
- // Vite 配置级别覆盖: CSR 直接返回空壳
142
- const overrideMode = matchRenderMode(url);
143
- if (overrideMode === "csr") {
144
- return c.html(injectCSRShell(TEMPLATE, getLocaleAttrs(DEFAULT_LOCALE)));
145
- }
146
-
147
- // ISR 缓存命中
148
- const cached = await platformCacheGet(url);
149
- if (cached) return c.html(cached);
150
-
151
- const { html: appHtml, head, css, serverData, renderMode, locale } = await render(url, { fetch: _createInternalFetch(_ssrDepth + 1) });
152
- const localeAttrs = getLocaleAttrs(locale || DEFAULT_LOCALE);
153
-
154
- // 路由级 CSR
155
- if (renderMode === "csr") {
156
- return c.html(injectCSRShell(TEMPLATE, localeAttrs));
157
- }
158
-
159
- const serializedData = serializeServerData(serverData);
160
- const finalHtml = injectSSR(TEMPLATE, head, css, appHtml, serializedData, localeAttrs);
161
-
162
- // Prerender ISR 缓存(包括 Vite 配置覆盖和路由级)
163
- if (renderMode === "prerender" || overrideMode === "prerender") {
164
- await platformCacheSet(url, finalHtml);
165
- ${t.platformPrerenderResponseHook??``}
166
- }
167
-
168
- return c.html(finalHtml);
169
- } catch (e) {
170
- console.error("[SSR Error]", e);
171
- return c.text("Internal Server Error", 500);
172
- }
173
- });
174
-
175
- ${t.platformExport}
176
- `}async function K(e,t){await e.vite.build({root:e.root,build:{ssr:t.entry,outDir:t.outDir,emptyOutDir:t.emptyOutDir??!0,target:t.target??`node18`,rollupOptions:{output:{entryFileNames:t.fileName??`index.mjs`}}},ssr:{noExternal:t.noExternal!==!1,external:[...t.external??nr,...rr]},resolve:e.resolvedResolve,css:e.resolvedCss})}function q(e,t,n){let{fs:r,path:i}=e;r.cpSync(i.resolve(e.root,`dist/client`),t,{recursive:!0}),n?.excludeHtml!==!1&&r.rmSync(i.join(t,`index.html`),{force:!0})}async function J(e){let{fs:t,path:n,root:r,vite:i}=e,{pathToFileURL:a}=await H(`node:url`),o=e.bootstrapEntry??`src/lib/bootstrap.ts`,s=[];if(t.existsSync(n.resolve(r,o))){await i.build({root:r,build:{ssr:o,outDir:n.resolve(r,`dist/server`),emptyOutDir:!1,rollupOptions:{output:{entryFileNames:`_routes_prerender.mjs`}}},resolve:e.resolvedResolve});let c=a(n.resolve(r,`dist/server/_routes_prerender.mjs`)).href,l=await H(c);s=l.routes??l.default??[],t.rmSync(n.resolve(r,`dist/server/_routes_prerender.mjs`),{force:!0})}let c=new Set;for(let e of s)e.renderMode===`prerender`&&e.path&&!e.path.includes(`:`)&&c.add(e.path);if(e.renderModes)for(let[t,n]of Object.entries(e.renderModes))n===`prerender`&&!t.includes(`*`)&&!t.includes(`:`)&&c.add(t);if(e.locales?.length){let t=[...c];for(let n of e.locales)for(let e of t){let t=e===`/`?`/${n}`:`/${n}${e}`;c.add(t)}}if(c.size===0)return[];let l=a(n.resolve(r,`dist/server/ssr.js`)).href,u=await H(l),d=[];for(let t of c)try{let{html:n,head:r,css:i,serverData:a,locale:o}=await u.render(t),s=u.serializeServerData(a),c=e.templateHtml.replace(/<!--ssr-([a-z][a-z0-9-]*)-->/g,(e,t)=>({head:r+`
177
- <style>`+i+`</style>`,body:n,data:`<script id="serialized-server-data" type="application/json">`+s+`<\/script>`})[t]??``);if(o){let{getLocaleAttributes:e}=await H(`@finesoft/core`),t=e(o);c=c.replace(/<html([^>]*)>/i,(e,n)=>`<html${n.replace(/\s+lang=("[^"]*"|'[^']*'|[^\s>]+)/gi,``).replace(/\s+dir=("[^"]*"|'[^']*'|[^\s>]+)/gi,``)} lang="${t.lang}" dir="${t.dir}">`)}d.push({url:t,html:c})}catch(e){console.warn(` [prerender] Failed to render ${t}:`,e)}return d.length>0&&console.log(` Pre-rendered ${d.length} pages (${c.size} routes)\n`),d}function ir(){return{name:`cloudflare`,async build(e){let{fs:t,path:n,root:r}=e,i=n.resolve(r,`dist/cloudflare`);t.rmSync(i,{recursive:!0,force:!0});let a=G(e,{platformImport:``,platformExport:`export default app;`,platformCache:`
178
- const ISR_CACHE_TTL = 3600; // 1 hour
179
- async function platformCacheGet(url) {
180
- try {
181
- const cache = caches.default;
182
- const cacheKey = new Request("https://isr-cache/" + encodeURIComponent(url));
183
- const resp = await cache.match(cacheKey);
184
- if (resp) return await resp.text();
185
- } catch {}
186
- return null;
187
- }
188
- async function platformCacheSet(url, html) {
189
- try {
190
- const cache = caches.default;
191
- const cacheKey = new Request("https://isr-cache/" + encodeURIComponent(url));
192
- const resp = new Response(html, {
193
- headers: { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "public, max-age=" + ISR_CACHE_TTL },
194
- });
195
- await cache.put(cacheKey, resp);
196
- } catch {}
197
- }`}),o=n.resolve(r,`.cf-entry.tmp.mjs`);t.writeFileSync(o,a);try{await K(e,{entry:`.cf-entry.tmp.mjs`,outDir:i,target:`es2022`,fileName:`_worker.js`}),q(e,n.resolve(i,`assets`));let r=await J(e);for(let{url:e,html:a}of r){let r=e===`/`?n.join(i,`assets`,`index.html`):n.join(i,`assets`,e,`index.html`);t.mkdirSync(n.resolve(r,`..`),{recursive:!0}),t.writeFileSync(r,a)}}finally{t.rmSync(o,{force:!0})}console.log(` Cloudflare output → dist/cloudflare/
198
- `)}}}function ar(){return{name:`netlify`,async build(e){let{fs:t,path:n,root:r}=e,i=n.resolve(r,`.netlify/functions-internal/ssr`);t.rmSync(n.resolve(r,`.netlify`),{recursive:!0,force:!0});let a=G(e,{platformImport:`import { handle } from "hono/netlify";`,platformExport:`export default handle(app);
199
- export const config = { path: "/*", preferStatic: true };`,platformCache:`
200
- const ISR_SWR_TTL = 3600;
201
- const ISR_CACHE_MAX = 1000;
202
- const _isrMap = new Map();
203
- async function platformCacheGet(url) {
204
- return _isrMap.get(url) ?? null;
205
- }
206
- async function platformCacheSet(url, html) {
207
- if (_isrMap.size >= ISR_CACHE_MAX) {
208
- const first = _isrMap.keys().next().value;
209
- _isrMap.delete(first);
210
- }
211
- _isrMap.set(url, html);
212
- }`,platformPrerenderResponseHook:`c.header("Cache-Control", "public, max-age=0, must-revalidate");
213
- c.header("Netlify-CDN-Cache-Control", "public, max-age=" + ISR_SWR_TTL + ", stale-while-revalidate=" + ISR_SWR_TTL + ", durable");`}),o=n.resolve(r,`.netlify-entry.tmp.mjs`);t.writeFileSync(o,a);try{await K(e,{entry:`.netlify-entry.tmp.mjs`,outDir:i,target:`node18`})}finally{t.rmSync(o,{force:!0})}t.writeFileSync(n.resolve(r,`dist/client/_redirects`),`/* /.netlify/functions/ssr 200
214
- `);let s=await J(e),c=n.resolve(r,`dist/client`);for(let{url:e,html:r}of s){let i=e===`/`?n.join(c,`index.html`):n.join(c,e,`index.html`);t.mkdirSync(n.resolve(i,`..`),{recursive:!0}),t.writeFileSync(i,r)}console.log(` Netlify output → .netlify/functions-internal/ssr/
215
- Publish dir: dist/client/
216
- `)}}}function or(){return{name:`node`,async build(e){let{fs:t,path:n,root:r}=e,i=G(e,{platformImport:`import { serve } from "@hono/node-server";
217
- import { readFileSync, existsSync } from "node:fs";
218
- import { resolve, dirname } from "node:path";
219
- import { fileURLToPath } from "node:url";`,platformMiddleware:`
220
- // 预渲染文件中间件:检查 dist/prerender/ 下是否有对应的静态 HTML
221
- const __entry_dirname = dirname(fileURLToPath(import.meta.url));
222
- const prerenderDir = resolve(__entry_dirname, "../prerender");
223
-
224
- app.use("*", async (c, next) => {
225
- const urlPath = c.req.path;
226
- const candidates = [
227
- resolve(prerenderDir, "." + urlPath, "index.html"),
228
- resolve(prerenderDir, "." + urlPath + ".html"),
229
- ];
230
- if (urlPath === "/") candidates.unshift(resolve(prerenderDir, "index.html"));
231
- for (const f of candidates) {
232
- if (existsSync(f)) {
233
- const html = readFileSync(f, "utf-8");
234
- return c.html(html);
235
- }
236
- }
237
- await next();
1
+ import { $ as isLeafNode, A as createActiveLeafCodec, At as getLocaleAttributes, B as findNode, Bt as secureFetch, C as runBeforeLoadGuards, Ct as defineApp, D as SERVER_REQUEST, Dt as implementOperation, E as SERVER_CONTROLLER, Et as implementController, F as serializeNavigation, Ft as englishPlural, G as push, Gt as ReportingLoggerFactory, H as pop, Ht as enforceHostGuard, I as serializeNavigationStable, It as interpolate, J as selectColumn, Jt as CompositeLogger, K as replaceTop, Kt as ConsoleLogger, L as collectAllLeaves, Lt as resolvePluralKey, M as decodeNavigationTreeParam, Mt as isRtl, N as encodeNavigationTreeParam, Nt as makeLocaleInfo, O as controllerContext, Ot as SimpleTranslator, P as deserializeNavigation, Pt as resolveLocaleFromUrl, Q as resourceKey, Qt as Container, R as collectVisibleDestinations, Rt as generateUuid, S as runAfterLoadGuards, St as createRuntime, T as getWebPlan, Tt as defineOperation, U as popTo, Ut as stableStringify, V as mapNavigationLeaves, Vt as fetchWithRedirects, W as popToRoot, Wt as ReportingLogger, X as setVisibility, Xt as isMultiValueSchema, Y as selectTab, Yt as CompositeLoggerFactory, Z as visibleSplitColumns, Zt as list, _ as SERVER_CONTROLLER_PATH, _t as isExternalUrlAction, a as createSessionStore, at as stack, b as decodeWireEnvelope, bt as makeFlowAction, c as decodeSnapshot, ct as NavigationError, d as createWebSession, dt as createHydrationDigest, et as isSplitNode, f as SESSION_DEFAULT_KEY, ft as PrefetchedIntents, g as loadPage, gt as isCompoundAction, h as StorageUnavailableError, ht as ACTION_KINDS, i as createWebRuntime, it as split, j as createFullStateCodec, jt as getTextDirection, k as DEFAULT_NAV_PARAM, kt as resolveMessages, l as encodeSnapshot, lt as SPLIT_VISIBILITIES, m as SessionError, mt as ActionDispatcher, n as definePage, nt as isTabsNode, o as collectLeafKeys, ot as tabs, p as SESSION_DEFAULT_VERSION, pt as Router, q as resolveActivePath, qt as ConsoleLoggerFactory, r as resolveInitialNavigation, rt as leaf, s as createNavigationScopedState, st as NAVIGATION_NODE_KINDS, t as parseCookieString, tt as isStackNode, u as NavigationCommitError, ut as route, v as ServerControllerProxy, vt as isFlowAction, w as defineWebApp, wt as defineModule, x as getFrameworkBuildId, xt as provide, y as FRAMEWORK_PROTOCOL_VERSION, yt as makeExternalUrlAction, z as findNearestStack, zt as detectPlatform } from "./src-BQBfaaPO.mjs";
2
+ import { C as bool, D as str, E as oneOf, O as uuid, S as withDefault, T as num, _ as mapEach, a as safeErrorPage, b as HttpClient, c as ConsoleEventRecorder, d as getBaseUrl, f as removeHost, g as isSome, h as isNone, i as rewrite, k as makeSchema, l as CompositeEventRecorder, m as removeScheme, n as next, o as WithFieldsRecorder, p as removeQueryParams, r as redirect, s as VoidEventRecorder, t as deny, u as buildUrl, v as pipe, w as int, x as optional, y as pipeAsync } from "./types-B1BT0N3t.mjs";
3
+ import { i as HttpError, n as classifyUrl, r as HostGuardError, t as classifyHost } from "./host-guard-DDWxLpFL.mjs";
4
+ import { n as ExecutionError, r as executionErrorFromHttp, t as compilePath } from "./path-CGFl2w7D.mjs";
5
+ import { a as isPublicMarked, i as getPublicFields, n as BASE_PAGE_FIELDS, o as markPublic, r as FINESOFT_PUBLIC, s as BaseController, t as resolveConfiguredMessages } from "./messages-CAt2QdGr.mjs";
6
+ import { t as LruMap } from "./lru-map-BKoUAySU.mjs";
7
+ import { n as createToken, t as DEP_KEYS } from "./src-Ftl_0rhu.mjs";
8
+ import { _ as tryScroll, a as shouldLog, c as createDomRestore, d as createSessionBridge, f as defaultShouldRestore, g as History, h as createNavigationBridge, i as resetFilterCache, l as createWebStorage, m as deserializeServerData, n as IntersectionImpressionObserver, o as createBrowserApp, p as createPrefetchedIntentsFromDom, r as getPWADisplayMode, s as createBrowserContext, t as setHtmlLocaleAttributes, u as SESSION_DEFAULT_DEBOUNCE_MS } from "./browser-CR5vhgXg.mjs";
9
+ import { a as serializeServerData, i as materializeServerData, n as createServerContext, r as createSSRRender, t as BaseServerController } from "./ssr-Tn4YkuxM.mjs";
10
+ import { c as injectSSRContent, i as matchRenderModeOverride, n as registerProxyRoutes, o as SSR_PLACEHOLDERS, r as createSSRHandler, s as injectCSRShell } from "./proxy-z02VvGIj.mjs";
11
+ import { n as defineEndpoint, r as runManagedTask, t as createHttpHandler } from "./http-D70PL72H.mjs";
12
+ import { loadImplementation } from "#finesoft/implementation";
13
+ //#region src/host-api.ts
14
+ const node = () => loadImplementation("node");
15
+ const vite = () => loadImplementation("vite");
16
+ const typegen = () => loadImplementation("typegen");
17
+ const startNodeHandler = (...args) => node().startNodeHandler(...args);
18
+ const nodeDnsLookup = (...args) => node().nodeDnsLookup(...args);
19
+ const nodeSafeFetchOptions = Object.freeze({
20
+ validateDns: false,
21
+ wrapFetch: (fetch) => node().nodeSafeFetchOptions.wrapFetch(fetch)
238
22
  });
239
- `,platformExport:`
240
- const port = +(process.env.PORT || 3000);
241
- serve({ fetch: app.fetch, port }, (info) => {
242
- console.log(\`Server running at http://localhost:\${info.port}\`);
243
- });
244
- `}),a=n.resolve(r,`.node-entry.tmp.mjs`);t.writeFileSync(a,i);try{await K(e,{entry:`.node-entry.tmp.mjs`,outDir:n.resolve(r,`dist/server`),target:`node18`,emptyOutDir:!1})}finally{t.rmSync(a,{force:!0})}let o=await J(e);if(o.length>0){let e=n.resolve(r,`dist/prerender`);t.mkdirSync(e,{recursive:!0});for(let{url:r,html:i}of o){let a=r===`/`?n.join(e,`index.html`):n.join(e,r,`index.html`);t.mkdirSync(n.resolve(a,`..`),{recursive:!0}),t.writeFileSync(a,i)}}console.log(` Node output → dist/server/index.mjs
245
- Run: node dist/server/index.mjs
246
- `)}}}function sr(e={}){return{name:`static`,async build(t){let{fs:n,path:r,root:i}=t,a=r.resolve(i,`dist/static`);n.rmSync(a,{recursive:!0,force:!0}),n.mkdirSync(a,{recursive:!0});let{pathToFileURL:o}=await H(`node:url`),s=o(r.resolve(i,`dist/server/ssr.js`)).href,c=await H(s);t.copyStaticAssets(a,{excludeHtml:!0});let{paths:l,defs:u}=await cr(t,e);console.log(` Pre-rendering ${l.length} pages...\n`);for(let e of l)try{let i=dr(e,u.find(t=>t.path===e)?.renderMode,t.renderModes),o;if(i===`csr`)o=ur(t.templateHtml);else{let{html:n,head:r,css:i,serverData:a}=await c.render(e),s=c.serializeServerData(a);o=lr(t.templateHtml,r,i,n,s)}let s=e===`/`?r.join(a,`index.html`):r.join(a,e,`index.html`);n.mkdirSync(r.resolve(s,`..`),{recursive:!0}),n.writeFileSync(s,o)}catch(t){console.warn(` [static] Failed to render ${e}:`,t)}console.log(` Static output → dist/static/
247
- `)}}}async function cr(e,t){let n=t.routesExport??`src/lib/bootstrap.ts`,r=[],i=[];try{let{pathToFileURL:t}=await H(`node:url`);await e.vite.build({root:e.root,build:{ssr:n,outDir:e.path.resolve(e.root,`dist/server`),emptyOutDir:!1,rollupOptions:{output:{entryFileNames:`_routes.mjs`}}},resolve:e.resolvedResolve});let a=t(e.path.resolve(e.root,`dist/server/_routes.mjs`)).href,o=await H(a),s=o.routes??o.default;if(Array.isArray(s))for(let e of s)e.path&&!e.path.includes(`:`)&&(r.push(e.path),i.push({path:e.path,renderMode:e.renderMode}));e.fs.rmSync(e.path.resolve(e.root,`dist/server/_routes.mjs`),{force:!0})}catch(e){console.warn(` [static] Could not load routes from "${n}". Using "/" only.`,e),r.length===0&&r.push(`/`)}if(t.dynamicRoutes)for(let e of t.dynamicRoutes)r.includes(e)||r.push(e);return r.length===0&&r.push(`/`),{paths:r,defs:i}}function lr(e,t,n,r,i){let a=/<!--ssr-([a-z][a-z0-9-]*)-->/g,o={head:t+`
248
- <style>`+n+`</style>`,body:r,data:`<script id="serialized-server-data" type="application/json">`+i+`<\/script>`};return e.replace(a,(e,t)=>o[t]??``)}function ur(e){return e.replace(/<!--ssr-([a-z][a-z0-9-]*)-->/g,()=>``)}function dr(e,t,n){if(n){if(n[e])return n[e];for(let[t,r]of Object.entries(n))if(t.includes(`*`)){let n=t.replace(/[.+?^${}()|[\]\\]/g,`\\$&`);if(RegExp(`^`+n.replace(/\*/g,`.*`)+`$`).test(e))return r}}return t??`ssr`}function fr(){return{name:`vercel`,async build(e){let{fs:t,path:n,root:r}=e,i=n.resolve(r,`.vercel/output`);t.rmSync(i,{recursive:!0,force:!0});let a=G(e,{platformImport:`import { getRequestListener } from "@hono/node-server";`,platformExport:[`const _listener = getRequestListener(app.fetch);`,`export default (req, res) => {`,` const m = req.headers["x-now-route-matches"];`,` if (typeof m === "string") {`,` try {`,` const p = new URLSearchParams(m);`,` const c = p.get("1");`,` if (c != null) {`,` const qi = (req.url || "").indexOf("?");`,` const qs = qi !== -1 ? req.url.slice(qi) : "";`,` req.url = "/" + decodeURIComponent(c) + qs;`,` }`,` } catch {}`,` }`,` return _listener(req, res);`,`};`].join(`
249
- `)}),o=n.resolve(r,`.vercel-entry.tmp.mjs`);t.writeFileSync(o,a);try{let i=n.resolve(r,`.vercel/output/functions/ssr.func`);await K(e,{entry:`.vercel-entry.tmp.mjs`,outDir:i,target:`node18`}),t.writeFileSync(n.resolve(i,`.vc-config.json`),JSON.stringify({runtime:`nodejs20.x`,handler:`index.mjs`,launcherType:`Nodejs`},null,2)),q(e,n.resolve(r,`.vercel/output/static`)),t.writeFileSync(n.resolve(r,`.vercel/output/config.json`),JSON.stringify({version:3,routes:[{handle:`filesystem`},{src:`/(.*)`,dest:`/ssr`}]},null,2))}finally{t.rmSync(o,{force:!0})}let s=await J(e),c=n.resolve(r,`.vercel/output/static`);for(let{url:e,html:r}of s){let i=e===`/`?n.join(c,`index.html`):n.join(c,e,`index.html`);t.mkdirSync(n.resolve(i,`..`),{recursive:!0}),t.writeFileSync(i,r)}if(s.length>0){let e=n.resolve(r,`.vercel/output/config.json`),i=JSON.parse(t.readFileSync(e,`utf-8`));i.overrides=i.overrides??{};for(let{url:e}of s){let t=e===`/`?`index.html`:`${e.replace(/^\//,``)}/index.html`;i.overrides[t]={path:e===`/`?`/`:e,contentType:`text/html; charset=utf-8`}}t.writeFileSync(e,JSON.stringify(i,null,2))}console.log(` Vercel output → .vercel/output/
250
- `)}}}function Y(e){if(typeof e!=`string`)return e;switch(e){case`vercel`:return fr();case`cloudflare`:return ir();case`netlify`:return ar();case`node`:return or();case`static`:return sr();case`auto`:return pr();default:throw Error(`[finesoft] Unknown adapter: "${e}". Available: vercel, cloudflare, netlify, node, static, auto`)}}function pr(){return{name:`auto`,async build(e){let t=mr();return console.log(` [auto] Detected platform: ${t}\n`),Y(t).build(e)}}}function mr(){return process.env.VERCEL?`vercel`:process.env.CF_PAGES?`cloudflare`:process.env.NETLIFY?`netlify`:`node`}function hr(e,t=1){return((n,r)=>{if(typeof n==`string`&&n.startsWith(`/`)){let i=new Request(`http://localhost${n}`,r);return i.headers.set(`x-ssr-depth`,String(t)),Promise.resolve(e(i))}return globalThis.fetch(n,r)})}function gr(e,t){if(!t)return null;let n=e.split(`?`)[0];if(t[n])return t[n];for(let[e,r]of Object.entries(t))if(e.includes(`*`)){let t=e.replace(/[.+?^${}()|[\]\\]/g,`\\$&`);if(RegExp(`^`+t.replace(/\*/g,`.*`)+`$`).test(n))return r}return null}function X(e){let{root:t,vite:n,isProduction:r,ssrEntryPath:i=`/src/ssr.ts`,ssrProductionModule:a,parentFetch:o,renderModes:s,defaultLocale:c}=e,l=new R,u=new D(1e3),d;async function f(e){if(!r&&n){let{readFileSync:r}=await H(`node:fs`),i=r((await H(`node:path`)).resolve(t,`index.html`),`utf-8`);return n.transformIndexHtml(e,i)}if(d)return d;if(globalThis.Deno!==void 0){let e=import.meta.url;return d=globalThis.Deno.readTextFileSync(new URL(`../dist/client/index.html`,e)),d}let{readFileSync:i}=await H(`node:fs`);return d=i((await H(`node:path`)).resolve(t,`dist/client/index.html`),`utf-8`),d}async function p(){if(!r&&n)return await n.ssrLoadModule(i);if(a)return H(a);let e=await H(`node:path`),{pathToFileURL:o}=await H(`node:url`),s=o(e.resolve(t,`dist/server/ssr.js`)).href;return H(s)}return l.get(`*`,async e=>{let t=parseInt(e.req.header(`x-ssr-depth`)??`0`,10);if(t>=5)return e.text(`SSR recursion loop detected`,508);let i=e.req.path+(e.req.url.includes(`?`)?`?`+e.req.url.split(`?`)[1]:``);try{let n=await f(i),r=await p();if(typeof r.render!=`function`||typeof r.serializeServerData!=`function`)throw Error(`[SSR] Module missing required exports: render, serializeServerData`);let{render:a,serializeServerData:l}=r,d=gr(i,s);if(d===`csr`)return e.html(V(n,c?N(c):void 0));let m=u.get(i);if(m)return e.html(m);let h=o?hr(o,t+1):void 0,g={request:e.req.raw};h&&(g.fetch=h);let{html:_,head:v,css:y,serverData:b,renderMode:x,redirect:S,slots:ee,locale:C,status:w,rewriteUrl:T}=await a(i,g);if(S)return e.redirect(S.url,S.status);if(x===`csr`)return e.html(V(n,C));let E=B({template:n,head:v,css:y,html:_,serializedData:l(b),slots:ee,locale:C});return(x===`prerender`||d===`prerender`)&&!w&&!T&&u.set(i,E),T&&e.header(`Content-Location`,T),w&&w>=400?e.html(E,w):e.html(E)}catch(t){return!r&&n&&n.ssrFixStacktrace(t),console.error(`[SSR Error]`,t),e.text(`Internal Server Error`,500)}}),l}function Z(){return{isDeno:globalThis.Deno!==void 0,isBun:globalThis.Bun!==void 0,isVercel:!!process.env.VERCEL,isProduction:process.env.NODE_ENV===`production`}}async function _r(e,t=0){if(globalThis.Deno!==void 0){let n=new URL(e);for(let e=0;e<t;e++)n=new URL(`..`,n);return n.pathname}let n=await H(`node:path`),{fileURLToPath:r}=await H(`node:url`),i=n.normalize(n.dirname(r(e)));for(let e=0;e<t;e++)i=n.resolve(i,`..`);return i}async function Q(e){let{app:t,root:n,port:r=3e3,isProduction:i,vite:a,routes:o,ssrEntryPath:s}=e,{isDeno:c,isBun:l,isVercel:u}=e.runtime??Z();function d(){let e=[`\n Server running at http://localhost:${r}\n`];if(o&&o.length>0){e.push(` Routes:`);for(let t of o)e.push(` ${t}`);e.push(``)}s&&e.push(` SSR Entry: ${s}`),s&&e.push(``),console.log(e.join(`
251
- `))}if(u)return{vite:a};if(!i){let e=a;if(!e){let{createServer:t}=await H(`vite`);e=await t({root:n,server:{middlewareMode:!0},appType:`custom`})}let{getRequestListener:i}=await H(`@hono/node-server`),{createServer:o}=await H(`node:http`),s=i(t.fetch);return o((t,n)=>{e.middlewares(t,n,()=>s(t,n))}).listen(r,()=>{d()}),{vite:e}}if(c)globalThis.Deno.serve({port:r},t.fetch);else if(!l){let{serveStatic:e}=await H(`@hono/node-server/serve-static`),i=await H(`node:path`),a=new R,o=i.resolve(n,`dist/client`);a.use(`/*`,e({root:o,rewriteRequestPath:e=>e.endsWith(`/`)?`/__nosuchfile__`:e})),a.route(`/`,t);let{serve:s}=await H(`@hono/node-server`);s({fetch:a.fetch,port:r},()=>{d()})}return{vite:a}}async function vr(e={}){let{root:t,port:n=Number(process.env.PORT)||3e3,setup:r,proxies:i,ssr:a}=e,o=t??process.cwd(),{existsSync:s}=await H(`node:fs`),c=(await H(`node:path`)).resolve(o,`.env`);if(s(c))try{let{config:e}=await H(`dotenv`);e({path:c})}catch(e){console.warn(`[Server] Failed to load .env: ${e.message}`)}let l=Z(),u;if(!l.isProduction&&!l.isVercel){let{createServer:e}=await H(`vite`);u=await e({root:o,server:{middlewareMode:!0},appType:`custom`})}let d=new R;i?.length&&W(d,i),r&&await r(d);let f=X({root:o,vite:u,isProduction:l.isProduction,parentFetch:d.fetch.bind(d),...a});return d.route(`/`,f),await Q({app:d,root:o,port:n,isProduction:l.isProduction,vite:u,runtime:l,ssrEntryPath:a?.ssrEntryPath}),{app:d,vite:u,runtime:l}}function yr(e,t,n){let r=t??[`zh`,`en`],i=n??r[0]??`en`;if(!e||e.length>1024)return i;let a=e.split(`,`);if(a.length>50)return i;let o=a.map(e=>{let[t,n]=e.trim().split(`;q=`),r=n?parseFloat(n):1;return{lang:t.trim().toLowerCase(),q:Number.isFinite(r)&&r>=0&&r<=1?r:0}}).filter(e=>e.q>0).sort((e,t)=>t.q-e.q);for(let{lang:e}of o){let t=e.split(`-`)[0];if(r.includes(t))return t}return i}const $=`virtual:finesoft-front/i18n-loader`,br=`\0${$}`;function xr(e){return typeof e.default==`function`?e.default:typeof e.setup==`function`?e.setup:Object.values(e).find(e=>typeof e==`function`)??null}function Sr(e,t){if(!t)return null;let n=e.split(`?`)[0];if(t[n])return t[n];for(let[e,r]of Object.entries(t))if(e.includes(`*`)){let t=e.replace(/[.+?^${}()|[\]\\]/g,`\\$&`);if(RegExp(`^`+t.replace(/\*/g,`.*`)+`$`).test(n))return r}return null}function Cr(e){return e.replace(/\\/g,`/`)}let wr=!1;function Tr(){wr||(wr=!0,console.log(`\n${(e=>`\x1b[33m${e}\x1b[0m`)(`[finesoft]`)} dev server is exposing source via /src/* and /@fs/* (HMR).\n`+(e=>`\x1b[2m${e}\x1b[0m`)(" Do NOT expose this server to untrusted networks; run `vp build && vp preview` for production.\n")))}async function Er(e,t){let{existsSync:n}=await H(`node:fs`),r=await H(`node:path`),i=r.isAbsolute(t)?t:r.resolve(e,t);if(!n(i))throw Error(`[finesoftFrontViteConfig] i18n.messagesDir not found: ${t}`);let a=Cr(r.relative(e,i));if(!a||a.startsWith(`..`))throw Error(`[finesoftFrontViteConfig] i18n.messagesDir must stay inside the project root: ${t}`);return a.replace(/^\.\/+/,``)}function Dr(e={}){let t=e.ssr?.entry??`src/ssr.ts`,n=process.cwd(),r,i,a,o=/\.(css|scss|less|sass|styl|stylus|pcss|postcss)($|\?)/;return{name:`finesoft-front`,config(t){let n={appType:`custom`,define:{__FINESOFT_I18N_LOADER_SPECIFIER__:e.i18n?.messagesDir?JSON.stringify($):`undefined`}};return process.env.__FINESOFT_SUB_BUILD__||(n.build={outDir:t.build?.outDir??`dist/client`}),n},configResolved(e){r=e.command,i=e.resolve,a=e.css,n=e.root},resolveId(t){return t===$&&e.i18n?.messagesDir?br:null},async load(t){if(t!==br||!e.i18n?.messagesDir)return null;let r=`/${await Er(n,e.i18n.messagesDir)}`,i=`${r}/*.json`,a=`${r}/`;return`
252
- const localeModules = import.meta.glob(${JSON.stringify(i)}, { import: "default" });
23
+ const finesoftFrontViteConfig = (...args) => vite().finesoftFrontViteConfig(...args);
24
+ const generateControllerTypes = (...args) => typegen().generateControllerTypes(...args);
25
+ const generateFrontTypes = (...args) => typegen().generateFrontTypes(...args);
26
+ const autoAdapter = (...args) => vite().autoAdapter(...args);
27
+ const cloudflareAdapter = (...args) => vite().cloudflareAdapter(...args);
28
+ const netlifyAdapter = (...args) => vite().netlifyAdapter(...args);
29
+ const nodeAdapter = (...args) => vite().nodeAdapter(...args);
30
+ const staticAdapter = (...args) => vite().staticAdapter(...args);
31
+ const vercelAdapter = (...args) => vite().vercelAdapter(...args);
32
+ const resolveAdapter = (...args) => vite().resolveAdapter(...args);
33
+ const generateProxyCode = (...args) => vite().generateProxyCode(...args);
34
+ //#endregion
35
+ //#region src/native-api.ts
36
+ function binding(renderer) {
37
+ if (renderer !== "react" && renderer !== "vue" && renderer !== "svelte") throw TypeError(`Unknown native renderer: ${String(renderer)}`);
38
+ return loadImplementation(renderer);
39
+ }
40
+ /** Select once, outside rendering, to retain native component identity and local state. */
41
+ const Outlet = (renderer) => binding(renderer).Outlet;
42
+ /** Uses the selected framework's native subscription and cleanup lifetime. */
43
+ const useSnapshot = (renderer, app) => binding(renderer).useSnapshot(app);
44
+ //#endregion
45
+ export { ACTION_KINDS, ActionDispatcher, BASE_PAGE_FIELDS, BaseController, BaseServerController, CompositeEventRecorder, CompositeLogger, CompositeLoggerFactory, ConsoleEventRecorder, ConsoleLogger, ConsoleLoggerFactory, Container, DEFAULT_NAV_PARAM, DEP_KEYS, ExecutionError, FINESOFT_PUBLIC, FRAMEWORK_PROTOCOL_VERSION, History, HostGuardError, HttpClient, HttpError, IntersectionImpressionObserver, LruMap, NAVIGATION_NODE_KINDS, NavigationCommitError, NavigationError, Outlet, PrefetchedIntents, ReportingLogger, ReportingLoggerFactory, Router, SERVER_CONTROLLER, SERVER_CONTROLLER_PATH, SERVER_REQUEST, SESSION_DEFAULT_DEBOUNCE_MS, SESSION_DEFAULT_KEY, SESSION_DEFAULT_VERSION, SPLIT_VISIBILITIES, SSR_PLACEHOLDERS, ServerControllerProxy, SessionError, SimpleTranslator, StorageUnavailableError, VoidEventRecorder, WithFieldsRecorder, autoAdapter, bool, buildUrl, classifyHost, classifyUrl, cloudflareAdapter, collectAllLeaves, collectLeafKeys, collectVisibleDestinations, compilePath, controllerContext, createActiveLeafCodec, createBrowserApp, createBrowserContext, createDomRestore, createFullStateCodec, createHttpHandler, createHydrationDigest, createNavigationBridge, createNavigationScopedState, createPrefetchedIntentsFromDom, createRuntime, createSSRHandler, createSSRRender, createServerContext, createSessionBridge, createSessionStore, createToken, createWebRuntime, createWebSession, createWebStorage, decodeNavigationTreeParam, decodeSnapshot, decodeWireEnvelope, defaultShouldRestore, defineApp, defineEndpoint, defineModule, defineOperation, definePage, defineWebApp, deny, deserializeNavigation, deserializeServerData, detectPlatform, encodeNavigationTreeParam, encodeSnapshot, enforceHostGuard, englishPlural, executionErrorFromHttp, fetchWithRedirects, findNearestStack, findNode, finesoftFrontViteConfig, generateControllerTypes, generateFrontTypes, generateProxyCode, generateUuid, getBaseUrl, getFrameworkBuildId, getLocaleAttributes, getPWADisplayMode, getPublicFields, getTextDirection, getWebPlan, implementController, implementOperation, injectCSRShell, injectSSRContent, int, interpolate, isCompoundAction, isExternalUrlAction, isFlowAction, isLeafNode, isMultiValueSchema, isNone, isPublicMarked, isRtl, isSome, isSplitNode, isStackNode, isTabsNode, leaf, list, loadPage, makeExternalUrlAction, makeFlowAction, makeLocaleInfo, makeSchema, mapEach, mapNavigationLeaves, markPublic, matchRenderModeOverride, materializeServerData, netlifyAdapter, next, nodeAdapter, nodeDnsLookup, nodeSafeFetchOptions, num, oneOf, optional, parseCookieString, pipe, pipeAsync, pop, popTo, popToRoot, provide, push, redirect, registerProxyRoutes, removeHost, removeQueryParams, removeScheme, replaceTop, resetFilterCache, resolveActivePath, resolveAdapter, resolveConfiguredMessages, resolveInitialNavigation, resolveLocaleFromUrl, resolveMessages, resolvePluralKey, resourceKey, rewrite, route, runAfterLoadGuards, runBeforeLoadGuards, runManagedTask, safeErrorPage, secureFetch, selectColumn, selectTab, serializeNavigation, serializeNavigationStable, serializeServerData, setHtmlLocaleAttributes, setVisibility, shouldLog, split, stableStringify, stack, startNodeHandler, staticAdapter, str, tabs, tryScroll, useSnapshot, uuid, vercelAdapter, visibleSplitColumns, withDefault };
253
46
 
254
- export async function loadMessages(locale) {
255
- const loader = localeModules[${JSON.stringify(a)} + locale + ".json"];
256
- if (!loader) return undefined;
257
- const messages = await loader();
258
- return messages ?? undefined;
259
- }
260
- `},transformIndexHtml:{order:`pre`,async handler(e,t){let n=t.server;if(!n)return;let r=(t.originalUrl||t.path||``).split(`?`)[0];if(/\.\w+$/.test(r)&&!r.endsWith(`.html`))return;let i=[...e.matchAll(/<script\b[^>]*\bsrc=["']([^"']+)["'][^>]*>/g)].find(e=>!e[1].startsWith(`/@`));if(!i)return;let a=i[1];try{await n.transformRequest(a)}catch{return}let s=[],c=new Set;function l(e,t=0){if(!(t>100)&&!(!e?.url||c.has(e.url))&&(c.add(e.url),o.test(e.url)&&!e.url.includes(`.svelte`)&&s.push(e.url),e.importedModules))for(let n of e.importedModules)l(n,t+1)}let u=await n.moduleGraph.getModuleByUrl(a);if(u&&l(u),s.length===0)return;let d=[];for(let e of s)try{let t=(await n.ssrLoadModule(e))?.default;typeof t==`string`&&t.length>0&&d.push({tag:`style`,attrs:{"data-vite-dev-id":e},children:t,injectTo:`head`})}catch{}return d}},configureServer(r){return async()=>{let{Hono:i}=await H(`hono`),{getRequestListener:a}=await H(`@hono/node-server`);Tr();let o=new i;if(e.proxies?.length&&W(o,e.proxies),typeof e.setup==`function`)await e.setup(o);else if(typeof e.setup==`string`){let t=xr(await r.ssrLoadModule(`/`+e.setup));t&&await t(o)}let s=X({root:n,vite:r,isProduction:!1,ssrEntryPath:`/`+t,parentFetch:o.fetch.bind(o),renderModes:e.renderModes,defaultLocale:e.defaultLocale});o.route(`/`,s);let c=a(o.fetch);r.middlewares.use((e,t)=>{c(e,t)})}},configurePreviewServer(t){return async()=>{let{readFileSync:r}=await H(`node:fs`),i=await H(`node:path`),{pathToFileURL:a}=await H(`node:url`),{Hono:o}=await H(`hono`),{getRequestListener:s}=await H(`@hono/node-server`),c=new o,l=new D(1e3);if(e.proxies?.length&&W(c,e.proxies),typeof e.setup==`function`)await e.setup(c);else if(typeof e.setup==`string`)try{let e=a(i.resolve(n,`dist/server/setup.mjs`)).href,t=xr(await H(e));t&&await t(c)}catch{console.warn(`[finesoft] Could not load setup module for preview. API routes disabled.`)}let u=r(i.resolve(n,`dist/client/index.html`),`utf-8`),d=a(i.resolve(n,`dist/server/ssr.js`)).href,f=await H(d);c.get(`*`,async t=>{let n=parseInt(t.req.header(`x-ssr-depth`)??`0`,10);if(n>=5)return t.text(`SSR recursion loop detected`,508);let r=t.req.path+(t.req.url.includes(`?`)?`?`+t.req.url.split(`?`)[1]:``);try{let i=Sr(r,e.renderModes);if(i===`csr`)return t.html(V(u,e.defaultLocale?N(e.defaultLocale):void 0));let a=l.get(r);if(a)return t.html(a);let{html:o,head:s,css:d,serverData:p,renderMode:m,redirect:h,slots:g,locale:_,status:v,rewriteUrl:y}=await f.render(r,{fetch:hr(c.fetch.bind(c),n+1)});if(h)return t.redirect(h.url,h.status);if(m===`csr`)return t.html(V(u,_));let b=B({template:u,head:s,css:d,html:o,serializedData:f.serializeServerData(p),slots:g,locale:_});return(m===`prerender`||i===`prerender`)&&!v&&!y&&l.set(r,b),y&&t.header(`Content-Location`,y),v&&v>=400?t.html(b,v):t.html(b)}catch(e){return console.error(`[SSR Preview Error]`,e),t.text(`Internal Server Error`,500)}});let p=s(c.fetch);t.middlewares.use((e,t)=>{p(e,t)})}},async closeBundle(){if(!process.env.__FINESOFT_SUB_BUILD__&&r===`build`){process.env.__FINESOFT_SUB_BUILD__=`1`;try{let r=await H(`vite`),o=await H(`node:fs`),s=await H(`node:path`);if(console.log(`
261
- Building SSR bundle...
262
- `),await r.build({root:n,build:{ssr:t,outDir:`dist/server`},ssr:{external:rr},resolve:i,css:a}),typeof e.setup==`string`&&(console.log(` Building setup module...
263
- `),await r.build({root:n,build:{ssr:e.setup,outDir:`dist/server`,emptyOutDir:!1,rollupOptions:{output:{entryFileNames:`setup.mjs`}}},resolve:i})),e.adapter){let c=Y(e.adapter),l=o.readFileSync(s.resolve(n,`dist/client/index.html`),`utf-8`),u={root:n,ssrEntry:t,setupPath:typeof e.setup==`string`?e.setup:void 0,bootstrapEntry:e.bootstrapEntry,templateHtml:l,renderModes:e.renderModes,proxies:e.proxies,locales:e.locales,defaultLocale:e.defaultLocale,resolvedResolve:i,resolvedCss:a,vite:r,fs:o,path:s,generateSSREntry(e){return G(u,e)},buildBundle(e){return K(u,e)},copyStaticAssets(e,t){return q(u,e,t)}};console.log(` Running adapter: ${c.name}...\n`),await c.build(u)}}finally{delete process.env.__FINESOFT_SUB_BUILD__}}}}}export{oe as ACTION_KINDS,x as ActionDispatcher,w as BASE_PAGE_FIELDS,s as BaseController,Oe as BaseLogger,an as CompositeEventRecorder,l as CompositeLogger,nn as CompositeLoggerFactory,gt as ConsoleEventRecorder,$t as ConsoleLogger,ln as ConsoleLoggerFactory,Me as Container,Mt as DEFAULT_NAV_PARAM,M as DEP_KEYS,Ne as FINESOFT_PUBLIC,I as Framework,ht as History,Te as HostGuardError,fn as HttpClient,o as HttpError,Re as IntentDispatcher,et as IntersectionImpressionObserver,D as LruMap,xe as NAVIGATION_NODE_KINDS,lt as NAVIGATION_OP_KINDS,Cn as NAVIGATION_TREE_INTENT_ID,y as NavigationError,ie as PrefetchedIntents,pt as ReportingLogger,Ye as ReportingLoggerFactory,Pt as Router,vt as SESSION_DEFAULT_DEBOUNCE_MS,ae as SESSION_DEFAULT_KEY,zt as SESSION_DEFAULT_VERSION,te as SPLIT_VISIBILITIES,vn as SSR_PLACEHOLDERS,ne as SessionError,je as SimpleTranslator,cn as VoidEventRecorder,Qt as WithFieldsRecorder,pr as autoAdapter,ct as bool,Ct as buildUrl,Fe as classifyHost,C as classifyUrl,ir as cloudflareAdapter,st as collectAllLeaves,Pe as collectLeafKeys,dt as collectVisibleDestinations,Ut as createActiveLeafCodec,ut as createAppHandle,m as createBrowserContext,at as createDomRestore,bt as createFlatStackCodec,$e as createFullStateCodec,Yt as createIslandOrchestrator,Tt as createNavigationBridge,L as createNavigationController,ee as createNavigationScopedState,we as createNavigationSessionAdapter,Wt as createPrefetchedIntentsFromDom,X as createSSRApp,Ln as createSSRNavigationRender,_n as createSSRRender,vr as createServer,d as createServerContext,Ze as createSessionBridge,a as createSessionStore,dn as createUrlSessionAdapter,Vt as createWebStorage,Ft as decodeNavigationTreeParam,Le as decodeSnapshot,Nt as defaultShouldRestore,e as defineNavigation,ot as defineRequestScopedKey,ze as defineRoute,Ge as defineRoutes,De as deny,j as deserializeNavigation,rt as deserializeServerData,Ot as detectPlatform,Z as detectRuntime,Kt as encodeNavigationTreeParam,b as encodeSnapshot,h as englishPlural,Mn as extractNavigationTree,Rt as findNearestStack,kt as findNode,Dr as finesoftFrontViteConfig,tr as generateProxyCode,ge as generateUuid,n as getBaseUrl,N as getLocaleAttributes,ye as getPWADisplayMode,A as getPublicFields,de as getTextDirection,V as injectCSRShell,B as injectSSRContent,Jt as int,f as interpolate,Bt as isCompoundAction,re as isExternalUrlAction,Ue as isFlowAction,g as isLeafNode,Et as isMultiValueSchema,_ as isNone,S as isPublicMarked,me as isRtl,T as isSome,p as isSplitNode,ve as isStackNode,wt as isTabsNode,He as isUrlLocation,O as islandContainerAttributes,i as leaf,Xt as list,Lt as makeDependencies,Be as makeExternalUrlAction,Ke as makeFlowAction,be as makeLocaleInfo,Gt as makeSchema,le as mapEach,se as markPublic,ar as netlifyAdapter,c as next,or as nodeAdapter,jt as num,Ht as oneOf,Ce as optional,yr as parseAcceptLanguage,Ee as pipe,pn as pipeAsync,_t as pop,mt as popTo,Xe as popToRoot,en as push,tn as redirect,It as registerActionHandlers,Je as registerExternalUrlHandler,Dt as registerFlowActionHandler,W as registerProxyRoutes,xt as removeHost,ue as removeQueryParams,pe as removeScheme,Jn as renderIslandsHtml,un as replaceTop,tt as resetFilterCache,nt as resolveActivePath,Y as resolveAdapter,P as resolveConfiguredMessages,qt as resolveIslandsShell,v as resolveLocaleFromUrl,r as resolveMessages,_e as resolvePluralKey,_r as resolveRoot,Ae as rewrite,Se as route,Ve as runAfterLoadGuards,qe as runBeforeLoadGuards,it as runStandard,Ie as safeErrorPage,ce as secureFetch,sn as selectColumn,ke as selectTab,F as serializeNavigation,Zt as serializeNavigationStable,Vn as serializeServerData,k as sessionEntryKey,E as setHtmlLocaleAttributes,u as setVisibility,on as shouldLog,St as split,z as ssrRender,wn as ssrRenderNavigation,We as stableStringify,fe as stack,At as startBrowserApp,Q as startServer,sr as staticAdapter,yt as str,Nn as stripNavigationTree,he as tabs,ft as tryScroll,Qe as uuid,fr as vercelAdapter,rn as visibleSplitColumns,t as withDefault};
264
47
  //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,5 @@
1
+ //#region src/load-node.d.ts
2
+ declare function loadImplementation(name: string): any;
3
+ //#endregion
4
+ export { loadImplementation };
5
+ //# sourceMappingURL=load-node.d.mts.map
@@ -0,0 +1,10 @@
1
+ import { createRequire } from "node:module";
2
+ //#region src/load-node.ts
3
+ const require = createRequire(import.meta.url);
4
+ function loadImplementation(name) {
5
+ return require(`./${name}.mjs`);
6
+ }
7
+ //#endregion
8
+ export { loadImplementation };
9
+
10
+ //# sourceMappingURL=load-node.mjs.map
@@ -0,0 +1,5 @@
1
+ //#region src/load-portable.d.ts
2
+ declare function loadImplementation(name: string): never;
3
+ //#endregion
4
+ export { loadImplementation };
5
+ //# sourceMappingURL=load-portable.d.mts.map
@@ -0,0 +1,8 @@
1
+ //#region src/load-portable.ts
2
+ function loadImplementation(name) {
3
+ throw Error(`[finesoft] ${name} requires its platform host. Use the finesoft Vite plugin for native UI bindings.`);
4
+ }
5
+ //#endregion
6
+ export { loadImplementation };
7
+
8
+ //# sourceMappingURL=load-portable.mjs.map
@@ -0,0 +1,50 @@
1
+ //#region ../core/src/utils/lru-map.ts
2
+ /**
3
+ * LruMap — 固定容量的 LRU 缓存
4
+ */
5
+ var LruMap = class {
6
+ map = /* @__PURE__ */ new Map();
7
+ capacity;
8
+ constructor(capacity) {
9
+ if (capacity < 1) throw new Error(`[LruMap] capacity must be >= 1, got ${capacity}`);
10
+ this.capacity = capacity;
11
+ }
12
+ get(key) {
13
+ if (!this.map.has(key)) return void 0;
14
+ const value = this.map.get(key);
15
+ this.map.delete(key);
16
+ this.map.set(key, value);
17
+ return value;
18
+ }
19
+ set(key, value) {
20
+ if (this.map.has(key)) this.map.delete(key);
21
+ else if (this.map.size >= this.capacity) {
22
+ const oldest = this.map.keys().next().value;
23
+ if (oldest !== void 0) this.map.delete(oldest);
24
+ }
25
+ this.map.set(key, value);
26
+ }
27
+ has(key) {
28
+ return this.map.has(key);
29
+ }
30
+ delete(key) {
31
+ return this.map.delete(key);
32
+ }
33
+ get size() {
34
+ return this.map.size;
35
+ }
36
+ clear() {
37
+ this.map.clear();
38
+ }
39
+ /** Iterate in eviction order: least recently used first. */
40
+ entries() {
41
+ return this.map.entries();
42
+ }
43
+ [Symbol.iterator]() {
44
+ return this.entries();
45
+ }
46
+ };
47
+ //#endregion
48
+ export { LruMap as t };
49
+
50
+ //# sourceMappingURL=lru-map-BKoUAySU.mjs.map
@@ -0,0 +1,140 @@
1
+ import { n as ExecutionError } from "./path-CGFl2w7D.mjs";
2
+ //#region ../core/src/intents/base-controller.ts
3
+ /**
4
+ * BaseController — 抽象 Intent Controller 基类
5
+ *
6
+ * 提供标准化的 try/catch → fallback 模式。
7
+ * 子类只需实现 execute() 和可选的 fallback()。
8
+ */
9
+ /**
10
+ * 抽象 Controller 基类
11
+ *
12
+ * 统一处理:
13
+ * - 类型安全的输入 (ControllerInput)
14
+ * - 返回类型约束 (TResult)
15
+ * - try/catch 错误处理 + 可选 fallback
16
+ *
17
+ * 路由生成的输入可直接使用 BaseController<Input, Result>。
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * const API = createToken<ApiClient>("api");
22
+ *
23
+ * type Input = ControllerInput<{ productId: string }>;
24
+ * class ProductController extends BaseController<Input, ProductPage> {
25
+ * async execute({ params, context }: Input) {
26
+ * const api = await context.get(API);
27
+ * return api.getProduct(params.productId);
28
+ * }
29
+ *
30
+ * fallback({ params }: ControllerFailure<{ productId: string }>) {
31
+ * return getMockProduct(params.productId);
32
+ * }
33
+ * }
34
+ * ```
35
+ */
36
+ var BaseController = class {
37
+ prepareContext(context) {
38
+ return context;
39
+ }
40
+ /**
41
+ * 错误回退 — 子类可选覆写
42
+ *
43
+ * 当 execute() 抛出异常时调用。
44
+ * 默认行为: 重新抛出原始错误。
45
+ *
46
+ * @param input - 操作输入与 execute() 抛出的 error
47
+ * @returns 回退数据
48
+ */
49
+ fallback({ error }) {
50
+ throw error;
51
+ }
52
+ /**
53
+ * 自动 try/catch → fallback 模式。
54
+ */
55
+ async perform(params, context, ...query) {
56
+ const input = {
57
+ params,
58
+ query: query[0] ?? {},
59
+ context: this.prepareContext(context)
60
+ };
61
+ try {
62
+ context.signal.throwIfAborted();
63
+ const result = await this.execute(input);
64
+ context.signal.throwIfAborted();
65
+ return result;
66
+ } catch (e) {
67
+ if (context.signal.aborted || e instanceof Error && e.name === "AbortError" || e instanceof ExecutionError && e.code === "cancelled") throw e;
68
+ const error = e instanceof Error ? e : new Error(String(e));
69
+ return this.fallback({
70
+ ...input,
71
+ error
72
+ });
73
+ }
74
+ }
75
+ };
76
+ //#endregion
77
+ //#region ../web/src/models/page.ts
78
+ /**
79
+ * 显式声明 page 对象里哪些字段可以跨 SSR/CSR 边界进入 HTML。未列出的字段在
80
+ * `serializeServerData` 时会被剥除,杜绝整 page 对象(含 apiToken、内部备注等)
81
+ * 被无意中 hydrate 到客户端的失误。
82
+ *
83
+ * 用 symbol 而非普通字段名:避免和应用自己的字段冲突,且 `JSON.stringify` 自动
84
+ * 忽略 symbol key,所以 marker 永远不会出现在序列化输出里。
85
+ */
86
+ const FINESOFT_PUBLIC = Symbol.for("finesoft.publicFields");
87
+ /** 标准 BasePage 字段 —— marker 缺失但显式标注时使用。 */
88
+ const BASE_PAGE_FIELDS = [
89
+ "id",
90
+ "pageType",
91
+ "title",
92
+ "description",
93
+ "url"
94
+ ];
95
+ function markPublic(page, publicFields) {
96
+ if (publicFields === true) {
97
+ Object.defineProperty(page, FINESOFT_PUBLIC, {
98
+ value: true,
99
+ enumerable: false,
100
+ configurable: true,
101
+ writable: false
102
+ });
103
+ return page;
104
+ }
105
+ Object.defineProperty(page, FINESOFT_PUBLIC, {
106
+ value: Object.freeze(Array.isArray(publicFields) ? [...publicFields] : { ...publicFields }),
107
+ enumerable: false,
108
+ configurable: true,
109
+ writable: false
110
+ });
111
+ return page;
112
+ }
113
+ /** True 如果 page 用 `markPublic` 显式标过。 */
114
+ function isPublicMarked(page) {
115
+ return typeof page === "object" && page !== null && page[FINESOFT_PUBLIC] !== void 0;
116
+ }
117
+ /** 取出 `markPublic` 写入的字段白名单;`true` 表示本层字段,`null` 表示未标注。 */
118
+ function getPublicFields(page) {
119
+ if (typeof page !== "object" || page === null) return null;
120
+ const v = page[FINESOFT_PUBLIC];
121
+ if (v === void 0) return null;
122
+ if (v === true) return true;
123
+ if (Array.isArray(v)) return v;
124
+ if (typeof v === "object" && v !== null) return v;
125
+ return null;
126
+ }
127
+ //#endregion
128
+ //#region ../web/src/i18n/messages.ts
129
+ /**
130
+ * Resolve the effective translation source for a locale.
131
+ */
132
+ async function resolveConfiguredMessages(options) {
133
+ const { locale, loadMessages, context } = options;
134
+ if (!locale || !context) return;
135
+ if (loadMessages) return loadMessages(locale, context);
136
+ }
137
+ //#endregion
138
+ export { isPublicMarked as a, getPublicFields as i, BASE_PAGE_FIELDS as n, markPublic as o, FINESOFT_PUBLIC as r, BaseController as s, resolveConfiguredMessages as t };
139
+
140
+ //# sourceMappingURL=messages-CAt2QdGr.mjs.map
@@ -0,0 +1,14 @@
1
+ import { g as WebAppView } from "./session-DnB4ZC3x.mjs";
2
+ //#region src/native-contract.d.ts
3
+ interface NativeBinding {
4
+ readonly Outlet: unknown;
5
+ useSnapshot(app: WebAppView): unknown;
6
+ }
7
+ /** One shared signature for the published API and project-specific declarations. */
8
+ interface NativeAPI<Bindings extends { [K in keyof Bindings]: NativeBinding; }> {
9
+ Outlet<R extends keyof Bindings>(renderer: R): Bindings[R]["Outlet"];
10
+ useSnapshot<R extends keyof Bindings>(renderer: R, app: WebAppView): ReturnType<Bindings[R]["useSnapshot"]>;
11
+ }
12
+ //#endregion
13
+ export { NativeBinding as n, NativeAPI as t };
14
+ //# sourceMappingURL=native-contract-DuR25hYB.d.mts.map
@@ -0,0 +1,2 @@
1
+ import { n as NativeBinding, t as NativeAPI } from "./native-contract-DuR25hYB.mjs";
2
+ export { NativeAPI, NativeBinding };