rosefc 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/deploy/Dockerfile.node +2 -2
- package/deploy/Dockerfile.static +5 -5
- package/deploy/cloudflare/functions/[[path]].ts +2 -2
- package/deploy/cloudflare/wrangler.toml +2 -2
- package/deploy/fly.toml +4 -4
- package/deploy/k8s/{rosefd.yaml → rosefc.yaml} +22 -22
- package/deploy/native/{RosefdApp.xcscheme → RosefcApp.xcscheme} +16 -16
- package/deploy/native/android.yml +3 -3
- package/deploy/native/flutter.yml +8 -8
- package/deploy/native/ios.yml +8 -8
- package/deploy/netlify/functions/{rosefd.ts → rosefc.ts} +5 -5
- package/deploy/netlify.toml +1 -1
- package/deploy/vercel.json +2 -2
- package/dist-cli/compiler.mjs +149 -149
- package/dist-cli/edge.mjs +14 -14
- package/dist-cli/export.mjs +546 -546
- package/dist-cli/{rosefd.mjs → rosefc.mjs} +398 -398
- package/dist-cli/runtime.mjs +2 -2
- package/dist-cli/test.mjs +159 -159
- package/package.json +7 -7
- package/src/FRAMEWORK_VERSION +1 -1
- package/src/cli/content.ts +1 -1
- package/src/cli/edge.ts +3 -3
- package/src/cli/prod-server.ts +12 -12
- package/src/cli/shell.ts +17 -17
- package/src/cli/shutdown.ts +3 -3
- package/src/runtime/db.ts +3 -3
- package/src/runtime/index.ts +60 -60
- package/src/types/{rosefd.d.ts → rosefc.d.ts} +12 -12
- /package/deploy/api/{rosefd.ts → rosefc.ts} +0 -0
package/dist-cli/edge.mjs
CHANGED
|
@@ -26,7 +26,7 @@ if (!__app) {
|
|
|
26
26
|
function __saveScroll() {
|
|
27
27
|
try {
|
|
28
28
|
const s = history.state || {};
|
|
29
|
-
history.replaceState(Object.assign({}, s, {
|
|
29
|
+
history.replaceState(Object.assign({}, s, { __rosefcScroll: window.scrollY }), '');
|
|
30
30
|
} catch (e) { /* history state unavailable (file:// edge): best effort */ }
|
|
31
31
|
}
|
|
32
32
|
function __navigate(pathname, restore) {
|
|
@@ -35,7 +35,7 @@ function __navigate(pathname, restore) {
|
|
|
35
35
|
if (restore) {
|
|
36
36
|
// back/forward: restore the entry's scroll (top when it has none)
|
|
37
37
|
const s = history.state || {};
|
|
38
|
-
const y = typeof s.
|
|
38
|
+
const y = typeof s.__rosefcScroll === 'number' ? s.__rosefcScroll : 0;
|
|
39
39
|
return Promise.resolve(p).then(() => { window.scrollTo(0, y); }, () => { window.scrollTo(0, y); });
|
|
40
40
|
}
|
|
41
41
|
// a fresh navigation starts at the top, like a full page load
|
|
@@ -59,7 +59,7 @@ document.addEventListener('click', (e) => {
|
|
|
59
59
|
});
|
|
60
60
|
// Prefetch the target route's full render (including $data) on hover, keyboard
|
|
61
61
|
// focus, or touch - the click that follows paints from cache: no await, no
|
|
62
|
-
// request. Other frameworks prefetch data only;
|
|
62
|
+
// request. Other frameworks prefetch data only; Rosefc prefetches the render
|
|
63
63
|
// because the inlined bundle already contains every route.
|
|
64
64
|
function __prefetchHandler(e) {
|
|
65
65
|
const a = e.target.closest && e.target.closest('a[href^="/"]');
|
|
@@ -109,20 +109,20 @@ document.addEventListener('submit', (e) => {
|
|
|
109
109
|
// running page. Both are DIRECT references (no wrapper arrow): the names take
|
|
110
110
|
// no arguments, so the call is identical and every document that carries the
|
|
111
111
|
// bundle pays eleven bytes for the pair instead of forty.
|
|
112
|
-
window.
|
|
112
|
+
window.__rosefc = { state: serializeState, prefetch: prefetchStats };
|
|
113
113
|
// initial=true: DOM is SSR output, resume state + wire markers (zero hydration).
|
|
114
114
|
// If the document was rendered for a DIFFERENT route (a static-file server's
|
|
115
115
|
// SPA fallback serves index.html for unknown paths), adopt nothing - let the
|
|
116
116
|
// client router render the requested route from scratch.
|
|
117
|
-
const __st = document.getElementById('
|
|
117
|
+
const __st = document.getElementById('__rosefc_state');
|
|
118
118
|
let __state = __st ? JSON.parse(__st.textContent || '{}') : {};
|
|
119
119
|
// The dev server's reload bridge hands the pre-reload signal graph back inside
|
|
120
|
-
// the next document (window.
|
|
120
|
+
// the next document (window.__rosefc_resume). The resumed values win over the
|
|
121
121
|
// fresh render's, but the ROUTE stays the one the server just rendered - and
|
|
122
122
|
// the route renders client-side from the bundle rather than adopting the SSR
|
|
123
123
|
// DOM, because a resumed list can be longer than the document's rows and
|
|
124
124
|
// adoption could not add them. Absent in every non-dev document.
|
|
125
|
-
const __resumed = window.
|
|
125
|
+
const __resumed = window.__rosefc_resume ? JSON.parse(window.__rosefc_resume) : null;
|
|
126
126
|
if (__resumed) {
|
|
127
127
|
const __route = __state.__route;
|
|
128
128
|
__state = Object.assign(__state, __resumed);
|
|
@@ -142,7 +142,7 @@ if (__state.__notFound) {
|
|
|
142
142
|
// layout): defer the initial wire() until the browser is idle so the SSR
|
|
143
143
|
// paint is interactive-to-paint without blocking on the event wiring. Falls
|
|
144
144
|
// back to eager wiring where requestIdleCallback is unavailable.
|
|
145
|
-
if (window.
|
|
145
|
+
if (window.__rosefcLazy && typeof requestIdleCallback === 'function') {
|
|
146
146
|
requestIdleCallback(() => start(__app, window.location.pathname, true));
|
|
147
147
|
} else {
|
|
148
148
|
start(__app, window.location.pathname, true);
|
|
@@ -150,7 +150,7 @@ if (__state.__notFound) {
|
|
|
150
150
|
} else {
|
|
151
151
|
start(__app, window.location.pathname);
|
|
152
152
|
}
|
|
153
|
-
`,H=null;function le(){if(H===null)if(globalThis.
|
|
153
|
+
`,H=null;function le(){if(H===null)if(globalThis.__ROSEFC_SKIP_MINIFY)H=V;else try{H=se.transformSync(V,{minify:!0}).code}catch{H=V}return H}var _e="style-src 'unsafe-inline'; img-src 'self' data: https://fastly.picsum.photos; font-src 'self' data:; connect-src 'self'; form-action 'self'; base-uri 'none'; frame-ancestors 'none'; object-src 'none'",Se={"x-content-type-options":"nosniff","x-frame-options":"DENY","referrer-policy":"strict-origin-when-cross-origin","permissions-policy":"accelerometer=(), autoplay=(), camera=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), usb=(), xr-spatial-tracking=()"},O=null,I=null;function ce(){let e=D();return(I===null||I.v!==e)&&(I={v:e,s:`
|
|
154
154
|
import { start, startNotFound, prefetch, postForm, prefetchStats, serializeState } from '${ie()}';
|
|
155
155
|
${le()}`}),I.s}var U=null;function ue(e){if(U!==null&&U.for===e)return U.out;let n=/\bexport\s*\{([^}]*)\}\s*;?\s*$/.exec(e),t=e,s="";n&&(t=e.slice(0,n.index)+e.slice(n.index+n[0].length),s=n[1].split(",").map(l=>{let u=l.split(" as ").map(d=>d.trim());return u.length===1||u[0]===u[1]?"":u[0]&&u[1]?`var ${u[1]} = ${u[0]};`:""}).join(""));let r=`
|
|
156
156
|
${t}
|
|
@@ -166,7 +166,7 @@ ${le()}`;return U={for:e,out:r},r}function z(){let e=new Uint8Array(16);crypto.g
|
|
|
166
166
|
.rn { display: inline-block; margin-left: 1.5rem; }
|
|
167
167
|
.rf { margin-top: 2rem; color: #888; font-size: 0.85rem; }
|
|
168
168
|
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .18s; }
|
|
169
|
-
`;var pe=Re.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^"']+/g,e=>e[0]==='"'||e[0]==="'"?e:e.replace(/\s+/g," ").replace(/\s*([:;{},])\s*/g,"$1").trim()).trim();function ke(e){let n=new Map,t=[],s=new Map,r=(l,u)=>{n.has(l)||(n.set(l,u),t.push(l))};for(let l of e){for(let u of l.matchAll(/<title[^>]*>[\s\S]*?<\/title>/gi))r("title",u[0]);for(let u of l.matchAll(/<(\w+)((?:\s+[\w:-]+(?:=(?:"[^"]*"|'[^']*'|[^\s"'>]+))?)*)\s*(?:\/>|>([\s\S]*?)<\/\1\s*>|>)/gi)){let d=u[1].toLowerCase();if(d==="title")continue;let b=u[2],p=S=>{let R=b.match(new RegExp(`\\s${S}=(?:"([^"]*)"|'([^']*)')`,"i"));return R?R[1]??R[2]:null},i=b.match(/\sid=(?:"([^"]*)"|'([^']*)')/i),m=p("name"),o=p("property"),f=p("rel"),w=p("charset"),c;m!==null?c=`${d}:${m}`:o!==null?c=`${d}:${o}`:f!==null?c=`${d}:${f}${$e(f,p)}`:w!==null?c=`${d}:${w}`:i?c=`${d}:${i[1]??i[2]}`:(c=`${d}:#${s.get(d)??0}`,s.set(d,(s.get(d)??0)+1)),c=c.replace(/"/g,"");let v=u[0].replace(/^<\w+/,S=>`${S} data-
|
|
169
|
+
`;var pe=Re.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^"']+/g,e=>e[0]==='"'||e[0]==="'"?e:e.replace(/\s+/g," ").replace(/\s*([:;{},])\s*/g,"$1").trim()).trim();function ke(e){let n=new Map,t=[],s=new Map,r=(l,u)=>{n.has(l)||(n.set(l,u),t.push(l))};for(let l of e){for(let u of l.matchAll(/<title[^>]*>[\s\S]*?<\/title>/gi))r("title",u[0]);for(let u of l.matchAll(/<(\w+)((?:\s+[\w:-]+(?:=(?:"[^"]*"|'[^']*'|[^\s"'>]+))?)*)\s*(?:\/>|>([\s\S]*?)<\/\1\s*>|>)/gi)){let d=u[1].toLowerCase();if(d==="title")continue;let b=u[2],p=S=>{let R=b.match(new RegExp(`\\s${S}=(?:"([^"]*)"|'([^']*)')`,"i"));return R?R[1]??R[2]:null},i=b.match(/\sid=(?:"([^"]*)"|'([^']*)')/i),m=p("name"),o=p("property"),f=p("rel"),w=p("charset"),c;m!==null?c=`${d}:${m}`:o!==null?c=`${d}:${o}`:f!==null?c=`${d}:${f}${$e(f,p)}`:w!==null?c=`${d}:${w}`:i?c=`${d}:${i[1]??i[2]}`:(c=`${d}:#${s.get(d)??0}`,s.set(d,(s.get(d)??0)+1)),c=c.replace(/"/g,"");let v=u[0].replace(/^<\w+/,S=>`${S} data-rosefc-head="${c}"`);r(c,v)}}return t.map(l=>n.get(l)).join(`
|
|
170
170
|
`)}function $e(e,n){return/(^|\s)canonical(\s|$)/i.test(e)?"":`@${n("href")??n("type")??n("as")??""}`}function Y(e,n=""){let t=n?` nonce="${n}"`:"";if(e)return`<script type="module"${t}>${ue(e)}</script>`;let s=ie();return`${`<link rel="modulepreload" href="${s}" crossorigin>`}
|
|
171
171
|
<script type="module"${t} src="${s}" fetchpriority="high"></script>
|
|
172
172
|
<script type="module"${t}>${ce()}</script>`}function fe(e=ae(),n="en",t="",s=!0){let r=e?`
|
|
@@ -177,14 +177,14 @@ ${le()}`;return U={for:e,out:r},r}function z(){let e=new Uint8Array(16);crypto.g
|
|
|
177
177
|
<head>
|
|
178
178
|
<meta charset="UTF-8">
|
|
179
179
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
180
|
-
<title>
|
|
180
|
+
<title>Rosefc</title>${l}${r}
|
|
181
181
|
${he}
|
|
182
182
|
</head>
|
|
183
|
-
<body>${u}`}function me(e,n,t,s=[],r=ae(),l=!0,u="en",d="",b="",p=!0){let i=ke(s),m=b?i.replace(/<script\b([^>]*)>/gi,(T,a)=>/\bnonce=/.test(a)?T:`<script${a} nonce="${b}">`):i,o=` lang="${u}"${d?` dir="${d}"`:""}`,f="",w=m.replace(/<(html|body)\b([^>]*)>/gi,(T,a,h)=>{let y=h.replace(/\s*data-
|
|
183
|
+
<body>${u}`}function me(e,n,t,s=[],r=ae(),l=!0,u="en",d="",b="",p=!0){let i=ke(s),m=b?i.replace(/<script\b([^>]*)>/gi,(T,a)=>/\bnonce=/.test(a)?T:`<script${a} nonce="${b}">`):i,o=` lang="${u}"${d?` dir="${d}"`:""}`,f="",w=m.replace(/<(html|body)\b([^>]*)>/gi,(T,a,h)=>{let y=h.replace(/\s*data-rosefc-head="[^"]*"/,"");return a==="html"?o=y:f=y,""}),c=/<title>/i.test(i)?"":"<title>Rosefc</title>",v=/rel=["']?icon/i.test(i)?"":`
|
|
184
184
|
${he}`,S=w?`
|
|
185
185
|
${w}`:"",R=r?`
|
|
186
186
|
<style>${r}</style>`:"",A=n.replace(/</g,"\\u003c"),Q=l?`
|
|
187
|
-
<script type="application/json" id="
|
|
187
|
+
<script type="application/json" id="__rosefc_state">${A}</script>
|
|
188
188
|
${Y(t,b)}`:"",g=l&&p?'<div id="app">':"",F=l&&p?"</div>":"",x=l&&p?`
|
|
189
189
|
<style>${pe}</style>`:"";return`<!DOCTYPE html>
|
|
190
190
|
<html${o}>
|
|
@@ -196,4 +196,4 @@ ${le()}`;return U={for:e,out:r},r}function z(){let e=new Uint8Array(16);crypto.g
|
|
|
196
196
|
<body${f}>
|
|
197
197
|
${g}${e}${F}${Q}
|
|
198
198
|
</body>
|
|
199
|
-
</html>`}function ge(e,n,t){let s=String(t("accept-language")??"").trim().toLowerCase(),r=n?.(e)??[];return r.length?[s,...r.map(l=>String(t(l)??"").trim())]:[s]}var M=[],E=null;globalThis.
|
|
199
|
+
</html>`}function ge(e,n,t){let s=String(t("accept-language")??"").trim().toLowerCase(),r=n?.(e)??[];return r.length?[s,...r.map(l=>String(t(l)??"").trim())]:[s]}var M=[],E=null;globalThis.__rosefcOnShutdown=we;globalThis.__rosefcRunShutdownHooks=ye;function we(e,n){let t={name:e,fn:n};return M.push(t),()=>{let s=M.indexOf(t);s!==-1&&M.splice(s,1)}}function ye(e){return E||(E=(async()=>{let n=[];for(let t of M.slice())try{await t.fn(),n.push({name:t.name,ok:!0})}catch(s){let r=s instanceof Error?s.message:String(s);n.push({name:t.name,ok:!1,error:r}),console.error(`[rosefc] shutdown hook ${t.name} failed (${e}):`,r)}return n})().finally(()=>{E=null}),E)}function xe(){return M.length}function Ce(e){let n=e.method;if(n!=="POST"&&n!=="PUT"&&n!=="PATCH"&&n!=="DELETE")return null;let t=e.headers.get("origin");if(t){let r;try{r=new URL(t).host}catch{return new Response("Cross-site request blocked (unparsable Origin header)",{status:403})}return r===new URL(e.url).host?null:new Response("Cross-site request blocked (Origin does not match Host)",{status:403})}let s=e.headers.get("sec-fetch-site");return s&&s!=="same-origin"&&s!=="same-site"&&s!=="none"?new Response(`Cross-site request blocked (sec-fetch-site: ${s})`,{status:403}):null}var be=Promise.resolve(),He=e=>{let n=be,t;return be=new Promise(s=>{t=s}),n.then(e).finally(t)};async function De(e,n){let t=n?.server??await import(Te(B(e,"server.js")).href),s=null,r="";if(n&&"client"in n)s=n.client??null;else try{s=await(await import("fs/promises")).readFile(B(e,"client.js"),"utf-8")}catch{s=null}s&&s.includes("chunks/")&&(s=null);let l=typeof t.sliceKeyFor=="function";l&&oe("sliced");let u=p=>l?J(t.sliceKeyFor(p),e):s;if(n&&"styles"in n)r=n.styles??"";else try{r=await(await import("fs/promises")).readFile(B(e,"styles.css"),"utf-8")}catch{r=""}let d=new Set;if(n&&"broken"in n)d=new Set(n.broken);else try{d=new Set(JSON.parse(await(await import("fs/promises")).readFile(B(e,"broken.json"),"utf-8")))}catch{d=new Set}let b=(p,i="")=>{let m={};for(let[f,w]of Object.entries(de(u(p),i)))m[f.toLowerCase()]=w;m["cache-control"]||(m["cache-control"]="no-cache");let o=t.headersFor?.(p);if(o)for(let[f,w]of Object.entries(o))m[f.toLowerCase()]=w;return m};return async function(i){let m=Ce(i);if(m)return m;let{pathname:o,searchParams:f}=new URL(i.url),w=o.replace(/\/+$/,"")||"/";return w!==o?new Response(null,{status:308,headers:{location:w+new URL(i.url).search}}):He(async()=>{t.setQuery?.(Object.fromEntries(f));let c=t.hasRequestHooks||t.hasResponseHooks?{request:i,url:new URL(i.url),method:i.method,pathname:o,state:{}}:null;if(c){let a=await t.runRequestHooks(c);if(a)return t.runResponseHooks(c,a)}if(t.middleware){let a=await t.runMiddleware(i);if(a)return c?t.runResponseHooks(c,a):a}if(o==="/__rosefc/data"&&i.method==="GET"){let a=f.get("path")||"/";try{if(t.middleware){let k=await t.runMiddleware(new Request(new URL(a,i.url),{method:"GET",headers:i.headers}));if(k){let L=new Headers(k.headers);return L.set("access-control-allow-origin","*"),new Response(await k.arrayBuffer(),{status:k.status,headers:L})}}t.setQuery?.(Object.fromEntries(new URL("http://x"+a).searchParams));let h=await t.renderPage(a,void 0,{withState:!0}),y={};try{y=JSON.parse(h?.state||"{}")}catch{y={}}return new Response(JSON.stringify({path:a,status:h?.status??200,state:y}),{status:200,headers:{"content-type":"application/json; charset=utf-8","access-control-allow-origin":"*","cache-control":"no-store"}})}catch(h){return new Response(JSON.stringify({error:String(h?.message??h).slice(0,200)}),{status:500,headers:{"content-type":"application/json; charset=utf-8","access-control-allow-origin":"*"}})}}if(t.isApi(o)){if(i.method!=="GET"){let h=t.invalidateRenderCache;typeof h=="function"&&h()}let a=await t.handleApi(i.method,o,i);return c?t.runResponseHooks(c,a):a}let v=i.method==="POST"?await i.formData():void 0;if(v){let a=t.invalidateRenderCache;typeof a=="function"&&a()}if(!v&&!d.has(o)&&!t.isBuffered?.(o)&&t.canStream(o)&&!t.isNoJs(o)&&!i.headers.get("x-pjax")){let a=t.cspNonce?.(o)?z():"",h=new Response(null,{status:200,headers:{"content-type":"text/html; charset=utf-8",...b(o,a)}}),y=c?await t.runResponseHooks(c,h):h,k=new TextEncoder,L=new ReadableStream({async start(W){let G=t.docAttrs(o);await t.renderPageStream(o,ve=>W.enqueue(k.encode(ve)),fe(r,G.lang,G.dir,!t.shellOff?.(o)),Y(u(o),a)),W.close()}});return new Response(L,{status:y.status,headers:y.headers})}let S=i.headers.get("cookie")||"",R=f.toString(),A=ge(o,t.hotVaryFor,a=>i.headers.get(a)).join("\0"),g=(!v&&t.isCachedRoute?.(o)?t.peekRenderCache?.(o,S,R,A):null)??(t.renderPageCached&&!v?await t.renderPageCached(o,S,R,A):await t.renderPage(o,v)),F=t.cspNonce?.(o)?z():"";if(g.redirect){let a=g.redirect,h=new URL(a,i.url),y=`<!DOCTYPE html><title>Redirecting</title><p>Redirecting to <a href="${a}">${a}</a>.</p>`;return new Response(y,{status:g.status??302,headers:{"content-type":"text/html; charset=utf-8",location:h.pathname+h.search}})}let x=me(g.html,g.state,u(o),g.head,r,g.csr!==!1,g.lang,g.dir,F,g.shell!==!1);i.headers.get("x-pjax")&&(x=Oe(x));let T=new Response(x,{status:g.status??200,headers:{"content-type":"text/html; charset=utf-8",...b(o,F)}});return c?t.runResponseHooks(c,T):T})}}function Oe(e){let n=e.indexOf('<main id="sk-main"');if(n<0)return e;let t=e.indexOf("</main>",n);if(t<0)return e;let s=e.slice(n,t+7),r=e.match(/<title>([\s\S]*?)<\/title>/i);return(r?r[0]:"")+s}export{De as createEdgeHandler,we as onShutdown,ye as runShutdownHooks,xe as shutdownHookCount};
|