@lomray/vite-ssr-boost 8.2.0 → 8.3.0-beta.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/README.md +21 -13
- package/SECURITY.md +1 -1
- package/adapters/express/entry.d.ts +1 -1
- package/adapters/express/entry.js.map +1 -1
- package/adapters/express/render.d.ts +4 -1
- package/adapters/express/render.js +1 -1
- package/adapters/express/render.js.map +1 -1
- package/browser/entry.js +1 -1
- package/browser/entry.js.map +1 -1
- package/browser/stream.d.ts +5 -0
- package/browser/stream.js +2 -0
- package/browser/stream.js.map +1 -0
- package/core/compose-html.d.ts +3 -4
- package/core/compose-html.js +1 -1
- package/core/compose-html.js.map +1 -1
- package/core/data-stream.d.ts +50 -0
- package/core/data-stream.js +2 -0
- package/core/data-stream.js.map +1 -0
- package/core/html-boundary.d.ts +7 -0
- package/core/html-boundary.js +2 -0
- package/core/html-boundary.js.map +1 -0
- package/core/render.d.ts +7 -1
- package/core/render.js +1 -1
- package/core/render.js.map +1 -1
- package/core/script.d.ts +6 -0
- package/core/script.js +2 -0
- package/core/script.js.map +1 -0
- package/edge/render-to-stream.js +1 -1
- package/edge/render-to-stream.js.map +1 -1
- package/helpers/build-custom-state.d.ts +1 -1
- package/helpers/build-custom-state.js +1 -1
- package/helpers/build-custom-state.js.map +1 -1
- package/helpers/build-router-state.d.ts +1 -1
- package/helpers/build-router-state.js +1 -1
- package/helpers/build-router-state.js.map +1 -1
- package/node/render-to-stream.js +1 -1
- package/node/render-to-stream.js.map +1 -1
- package/package.json +13 -5
- package/services/diagnostics.d.ts +8 -3
- package/services/diagnostics.js +1 -1
- package/services/diagnostics.js.map +1 -1
package/README.md
CHANGED
|
@@ -20,18 +20,6 @@
|
|
|
20
20
|
|
|
21
21
|
## Quick start
|
|
22
22
|
|
|
23
|
-
**Start a new app** with the `minimal` template (default):
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm create @lomray/ssr-app@latest my-app
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Choose the `full` template by passing the flag after `--`:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npm create @lomray/ssr-app@latest my-app -- --template full
|
|
33
|
-
```
|
|
34
|
-
|
|
35
23
|
**Add to an existing app:**
|
|
36
24
|
|
|
37
25
|
```bash
|
|
@@ -50,8 +38,22 @@ The [migration guide](./docs/guide/migrate-existing-spa.md) walks through the fi
|
|
|
50
38
|
| `src/server.ts` | Add the server entry and request-scoped setup. |
|
|
51
39
|
| `package.json` | Use the `ssr-boost` dev, build and start commands. |
|
|
52
40
|
|
|
41
|
+
**Start a new app** with the `minimal` template (default):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm create @lomray/ssr-app@latest my-app
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Choose the `full` template by passing the flag after `--`:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm create @lomray/ssr-app@latest my-app -- --template full
|
|
51
|
+
```
|
|
52
|
+
|
|
53
53
|
Starting a new app? Choose one of the [template branches](./docs/examples/index.md) with the [`npm create` command](./docs/guide/getting-started.md#create-a-new-app) or clone the branch directly.
|
|
54
54
|
|
|
55
|
+
To defer loader work, return `{ title, slow: fetchUsers() }` and render `slow` with Suspense and `<Await>`; see the [streaming guide](./docs/guide/data-streaming.md).
|
|
56
|
+
|
|
55
57
|
## Who this is for
|
|
56
58
|
|
|
57
59
|
- Teams adding SSR to a Vite SPA with React Router route objects.
|
|
@@ -66,10 +68,14 @@ Starting a new app? Choose one of the [template branches](./docs/examples/index.
|
|
|
66
68
|
- Your React version within the package's peer range: React and React DOM `>=18.2.0`.
|
|
67
69
|
- Your hosting choice, provided it can run the selected SSR transport or serve SPA files.
|
|
68
70
|
|
|
71
|
+
Loader and action promises support `<Await>` and React 19 `use()` during hydration by default. [Stream loader data](./docs/guide/data-streaming.md) shows the loader pattern and `hydration: 'early'` for shell interaction before slow boundaries finish.
|
|
72
|
+
|
|
69
73
|
## What you add
|
|
70
74
|
|
|
71
75
|
Add `SsrBoost()` to the Vite plugins, wire `client.ts` and `server.ts`, and replace the Vite scripts with `ssr-boost` commands. The [migration guide](./docs/guide/migrate-existing-spa.md) includes these entries and the HTML outlet, copied from the minimal example.
|
|
72
76
|
|
|
77
|
+
Deferred router data needs no additional state library. Keep footer hydration by default, or opt into early hydration with custom state available at `onShellReady`.
|
|
78
|
+
|
|
73
79
|
## Choose your server
|
|
74
80
|
|
|
75
81
|
**Managed CLI (default).** Use `ssr-boost dev` for Express with Vite development and HMR, then `ssr-boost build` and `ssr-boost start` for production assets and SSR. The server entry is `@lomray/vite-ssr-boost/adapters/express/entry`, with hooks for requests, rendering and responses.
|
|
@@ -84,7 +90,7 @@ Add `SsrBoost()` to the Vite plugins, wire `client.ts` and `server.ts`, and repl
|
|
|
84
90
|
|
|
85
91
|
## Install and template quick start
|
|
86
92
|
|
|
87
|
-
|
|
93
|
+
See [Compatibility](#compatibility) for the package Node requirement. The example uses Node 22.23.2; React Router and build tools can raise the required Node version.
|
|
88
94
|
|
|
89
95
|
Start with the [minimal template](https://github.com/Lomray-Software/vite-template/tree/example/minimal):
|
|
90
96
|
|
|
@@ -111,6 +117,8 @@ Already running this in production? Point our [free performance audit](https://a
|
|
|
111
117
|
|
|
112
118
|
## Compatibility
|
|
113
119
|
|
|
120
|
+
See the [support policy](./SUPPORT.md) for version lifetimes, response targets and breaking-change commitments, and [Upgrade from 7 to 8](./docs/guide/upgrade-v8.md) for migration instructions.
|
|
121
|
+
|
|
114
122
|
The package is tested against the current and previous major of React, React Router and Vite, with an additional Vite 6 row. The [compatibility workflow](./.github/workflows/react-compatibility.yml) runs the full test suite and a built Worker check on Node 22.23.2 with these exact combinations:
|
|
115
123
|
|
|
116
124
|
| React / React DOM | React Router | Vite |
|
package/SECURITY.md
CHANGED
|
@@ -13,7 +13,7 @@ When reporting security issues, please provide the following information:
|
|
|
13
13
|
- Steps to reproduce the vulnerability
|
|
14
14
|
- Your contact information
|
|
15
15
|
|
|
16
|
-
We
|
|
16
|
+
We will provide a human acknowledgment within **two business days** of receiving your security report. Business days are Monday through Friday, excluding public holidays observed by the responding maintainer. We will keep you informed while we investigate and coordinate a fix; acknowledgment does not mean resolution. See [Support policy](./SUPPORT.md) for the security maintenance windows.
|
|
17
17
|
|
|
18
18
|
## Responsible Disclosure
|
|
19
19
|
We adhere to the principle of responsible disclosure. This means that if you discover a vulnerability, you agree to:
|
|
@@ -15,7 +15,7 @@ export interface IInitServerRequestOut<T = Record<string, any>> {
|
|
|
15
15
|
shouldSkip?: boolean;
|
|
16
16
|
shouldCancel?: boolean;
|
|
17
17
|
}
|
|
18
|
-
export interface IEntrypointOptions<TAppProps = Record<string, any>> extends Pick<IRenderOptions<TAppProps>, 'onRouterReady' | 'onShellReady' | 'onShellError' | 'onResponse' | 'onError' | 'getState' | 'getBody'> {
|
|
18
|
+
export interface IEntrypointOptions<TAppProps = Record<string, any>> extends Pick<IRenderOptions<TAppProps>, 'onRouterReady' | 'onShellReady' | 'onShellError' | 'onResponse' | 'onError' | 'getState' | 'getBody' | 'hydration' | 'nonce' | 'bootstrapScriptContent'> {
|
|
19
19
|
onServerCreated?: (app: Express, serverApi: ServerApi) => Promise<void> | void;
|
|
20
20
|
onServerStarted?: (app: Express, serverApi: ServerApi, server: Server) => Promise<void> | void;
|
|
21
21
|
onRequest?: (req: Request, res: ExpressResponse) => Promise<IInitServerRequestOut<TAppProps>> | IInitServerRequestOut<TAppProps>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.js","sources":["../../../src/adapters/express/entry.tsx"],"sourcesContent":[null],"names":["entry","App","routes","init","routerOptions","rest","handler","createStaticHandler","render","bind"],"mappings":"
|
|
1
|
+
{"version":3,"file":"entry.js","sources":["../../../src/adapters/express/entry.tsx"],"sourcesContent":[null],"names":["entry","App","routes","init","routerOptions","rest","handler","createStaticHandler","render","bind"],"mappings":"8EA+EA,SAASA,EACPC,EACAC,GACAC,KAAEA,EAAIC,cAAEA,KAAkBC,GAAyC,IAEnE,MAAMC,EAAUC,EAAoBL,EAAyBE,GAE7D,MAAO,CACLI,OAAQA,EAAOC,KAAK,KAAM,CAAEH,UAASL,QACrCE,OACAD,YACGG,EAEP"}
|
|
@@ -26,6 +26,9 @@ export interface IRenderParams<TAppProps = Record<string, any>> {
|
|
|
26
26
|
handler: StaticHandler;
|
|
27
27
|
}
|
|
28
28
|
export interface IRenderOptions<TAppProps = Record<string, any>> {
|
|
29
|
+
hydration?: 'early' | 'footer';
|
|
30
|
+
nonce?: string;
|
|
31
|
+
bootstrapScriptContent?: string;
|
|
29
32
|
abortDelay?: number;
|
|
30
33
|
getBody?: (request: ExpressRequest) => BodyInit | null | undefined;
|
|
31
34
|
onRouterReady?: (params: {
|
|
@@ -61,5 +64,5 @@ export interface IShellReadyOut {
|
|
|
61
64
|
/**
|
|
62
65
|
* Render application
|
|
63
66
|
*/
|
|
64
|
-
declare function render({ App, handler }: IRenderParams, config: ServerConfig, initialContext: Omit<IRequestContext, 'request'>, { onRouterReady, onShellReady, onResponse, onShellError, onError, getBody, getState, abortDelay, }: IRenderOptions): Promise<void>;
|
|
67
|
+
declare function render({ App, handler }: IRenderParams, config: ServerConfig, initialContext: Omit<IRequestContext, 'request'>, { onRouterReady, onShellReady, onResponse, onShellError, onError, getBody, getState, hydration, nonce, bootstrapScriptContent, abortDelay, }: IRenderOptions): Promise<void>;
|
|
65
68
|
export default render;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"chalk";import
|
|
1
|
+
import e from"chalk";import t from"react";import r from"./create-request.js";import o from"../../constants/stream-error.js";import s from"../../core/early-hints.js";import{getHeaderEntries as n,getSetCookieHeaders as a}from"../../core/headers.js";import i from"../../core/render.js";import d from"../../node/render-to-stream.js";import c from"../../node/request-signal.js";import p from"../../node/write-early-hints.js";import m,{writeFetchHeaders as l}from"../../node/write-fetch-response.js";import u,{isDiagnosticsEnabled as h}from"../../services/diagnostics.js";import f from"../../services/ssr-manifest.js";const y=(e,t,o)=>{const s={signal:t};return o&&"GET"!==e.method&&"HEAD"!==e.method&&(s.body=o(e)??null),r(e,s)};async function x({App:r,handler:x},g,S,{onRouterReady:E,onShellReady:w,onResponse:C,onShellError:j,onError:v,getBody:R,getState:b,hydration:q,nonce:A,bootstrapScriptContent:H,abortDelay:k=15e3}){const{appProps:D,html:L,req:P,res:T}=S,O=g.getLogger(),B=c(P,T);try{const c=Object.assign(S,{request:y(P,B.signal,R)}),G={appProps:D,diagnostics:h(!g.isProd)?new u(new URL(c.request.url).pathname,O):void 0,html:L,request:c.request,response:{headers:new Headers}},U=e=>(c.request=e.request,c.didError=e.didError,c.html=e.html,c.isStream=e.isStream,c.routerContext=e.routerContext,c.serverContext=e.serverContext,c),$=await i({createApp:(e,o)=>t.createElement(r,{server:{...o.appProps,req:P}},e),handler:x,renderToStream:d},G,{abortDelay:k,hydration:q,nonce:A,bootstrapScriptContent:H,getState:b?({context:e})=>b({context:U(e)}):void 0,onError:({context:t,error:r})=>{const{code:s,message:n}=r;if(v?.({context:U(t),error:r}),O.info(e.red(`Stream error. Code: ${s}`)),[o.RenderAborted,o.RenderTimeout,o.RenderCancel].includes(s))return void O.info(e.dim(n));const{original:a}=r;O.error(a)},onResponse:C?({context:e,html:t,isEnd:r})=>C({context:U(e),html:t,isEnd:r}):void 0,onRouterReady:E?({context:e})=>E({context:U(e)}):void 0,onShellError:j?({context:e,error:t})=>j({context:U(e),error:t}):void 0,onShellReady:({context:e})=>{const t=U(e);((e,t)=>{if(t.headersSent||t.writableEnded)return;t.status(e.response.status??200),n(e.response.headers).forEach(([e,r])=>t.setHeader(e,r));const r=a(e.response.headers);r.length&&t.setHeader("Set-Cookie",r)})(e,T);const r=w?.({context:t});return((e,t)=>{const r=new Headers(e.response.headers);r.delete("Set-Cookie");for(const[e,o]of Object.entries(t.getHeaders()))if("set-cookie"!==e.toLowerCase()&&void 0!==o)if(Array.isArray(o))for(const t of o)r.append(e,t);else r.set(e,"number"==typeof o?String(o):o);e.response.headers=r,e.response.status=t.statusCode})(e,T),r??{}},prepare:async({context:e,executionContext:t})=>{const r=U(e),o=f.get(g);await o.prepareDevAssets(e.routerContext?.matches);const n=o.injectAssets(r);r.hasEarlyHints&&await s(t,n)},routerRequestContext:c},{onEarlyHints:e=>p(T,e)});U(G),await(async(e,t)=>{const r=t.headers.get("Location");if(r&&t.status>=300&&t.status<400&&!e.headersSent&&!e.writableEnded&&!e.destroyed)return l(e,t),await(t.body?.cancel()),void e.redirect(t.status,r);await m(e,t)})(T,$)}finally{B.dispose()}}export{x as default};
|
|
2
2
|
//# sourceMappingURL=render.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sources":["../../../src/adapters/express/render.tsx"],"sourcesContent":[null],"names":["createRenderRequest","req","signal","getBody","options","method","body","createFetchRequest","async","render","App","handler","config","initialContext","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","appProps","html","shellHtml","res","Logger","getLogger","requestSignal","createRequestSignal","context","Object","assign","request","coreContext","diagnostics","isDiagnosticsEnabled","isProd","Diagnostics","URL","url","pathname","undefined","response","headers","Headers","syncContext","updated","didError","isStream","routerContext","serverContext","coreRender","createApp","children","React","createElement","server","renderToStream","error","code","message","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","original","isEnd","legacyContext","headersSent","writableEnded","status","getHeaderEntries","forEach","name","value","setHeader","cookies","getSetCookieHeaders","length","prepareResponse","shell","delete","entries","getHeaders","toLowerCase","Array","isArray","item","append","set","String","statusCode","syncResponse","prepare","executionContext","manifest","SsrManifest","get","prepareDevAssets","matches","hints","injectAssets","hasEarlyHints","emitEarlyHints","routerRequestContext","onEarlyHints","writeEarlyHints","location","destroyed","writeFetchHeaders","cancel","redirect","writeFetchResponse","writeResponse","dispose"],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.js","sources":["../../../src/adapters/express/render.tsx"],"sourcesContent":[null],"names":["createRenderRequest","req","signal","getBody","options","method","body","createFetchRequest","async","render","App","handler","config","initialContext","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","hydration","nonce","bootstrapScriptContent","abortDelay","appProps","html","shellHtml","res","Logger","getLogger","requestSignal","createRequestSignal","context","Object","assign","request","coreContext","diagnostics","isDiagnosticsEnabled","isProd","Diagnostics","URL","url","pathname","undefined","response","headers","Headers","syncContext","updated","didError","isStream","routerContext","serverContext","coreRender","createApp","children","React","createElement","server","renderToStream","error","code","message","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","original","isEnd","legacyContext","headersSent","writableEnded","status","getHeaderEntries","forEach","name","value","setHeader","cookies","getSetCookieHeaders","length","prepareResponse","shell","delete","entries","getHeaders","toLowerCase","Array","isArray","item","append","set","String","statusCode","syncResponse","prepare","executionContext","manifest","SsrManifest","get","prepareDevAssets","matches","hints","injectAssets","hasEarlyHints","emitEarlyHints","routerRequestContext","onEarlyHints","writeEarlyHints","location","destroyed","writeFetchHeaders","cancel","redirect","writeFetchResponse","writeResponse","dispose"],"mappings":"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"}
|
package/browser/entry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"react";import t from"react-dom/client";import{matchRoutes as o,createBrowserRouter as
|
|
1
|
+
import e from"react";import t from"react-dom/client";import{matchRoutes as o,createBrowserRouter as r,RouterProvider as n}from"react-router";import a from"./stream.js";import{IS_SSR_MODE as i}from"../constants/common.js";async function c(c,d,{init:s,routerOptions:l,createRouter:m=r,rootId:u="root"}={}){const f=i?a():void 0,w=(()=>{const e="__staticRouterHydrationData";if(!("loading"!==document.readyState||i&&void 0!==Reflect.get(window,e)))return new Promise(t=>{const o=()=>{i&&Reflect.deleteProperty(window,e),t()};document.addEventListener("DOMContentLoaded",o,{once:!0}),i&&Object.defineProperty(window,e,{configurable:!0,enumerable:!0,get:()=>{},set:r=>{Object.defineProperty(window,e,{configurable:!0,enumerable:!0,writable:!0,value:r}),document.removeEventListener("DOMContentLoaded",o),t()}})})})(),y=o(d,window.location,l?.basename)?.filter(e=>e.route.lazy);(w||y?.length)&&await Promise.all([w,...(y??[]).map(async e=>{const{lazy:t}=e.route;if("function"==typeof t){const o=await t();o&&Object.assign(e.route,{...o,lazy:void 0})}})]);const p=Reflect.get(window,"__staticRouterHydrationData");f&&p?.__ssrBoostStream&&Reflect.set(window,"__staticRouterHydrationData",await f.ready);const R=m(d,l),b=document.getElementById(u),g=await(s?.({isSSRMode:i,router:R})),_=()=>e.createElement(c,{client:g},e.createElement(n,{router:R}));return i&&"1"!==b.dataset.forceSpa?t.hydrateRoot(b,e.createElement(_,null)):t.createRoot(b).render(e.createElement(_,null))}export{c as default};
|
|
2
2
|
//# sourceMappingURL=entry.js.map
|
package/browser/entry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.js","sources":["../../src/browser/entry.tsx"],"sourcesContent":[null],"names":["async","entry","App","routes","init","routerOptions","createRouter","createBrowserRouter","rootId","
|
|
1
|
+
{"version":3,"file":"entry.js","sources":["../../src/browser/entry.tsx"],"sourcesContent":[null],"names":["async","entry","App","routes","init","routerOptions","createRouter","createBrowserRouter","rootId","stream","IS_SSR_MODE","receiveStream","undefined","documentReady","hydrationKey","document","readyState","Reflect","get","window","Promise","resolve","onReady","deleteProperty","addEventListener","once","Object","defineProperty","configurable","enumerable","set","value","writable","removeEventListener","waitForDocument","lazyMatches","matchRoutes","location","basename","filter","m","route","lazy","length","all","map","lazyResult","assign","hydration","__ssrBoostStream","ready","router","root","getElementById","appProps","isSSRMode","AppComponent","React","createElement","client","RouterProvider","dataset","ReactDOM","hydrateRoot","createRoot","render"],"mappings":"6NA0EAA,eAAeC,EACbC,EACAC,GACAC,KACEA,EAAIC,cACJA,EAAaC,aACbA,EAAeC,EAAmBC,OAClCA,EAAS,QACyB,CAAA,GAEpC,MAAMC,EAASC,EAAcC,SAAkBC,EACzCC,EAvDgB,MACtB,MAAMC,EAAe,8BAErB,KAC0B,YAAxBC,SAASC,YACRN,QAAqDE,IAAtCK,QAAQC,IAAIC,OAAQL,IAKtC,OAAO,IAAIM,QAAeC,IACxB,MAAMC,EAAU,KACVZ,GACFO,QAAQM,eAAeJ,OAAQL,GAGjCO,KAGFN,SAASS,iBAAiB,mBAAoBF,EAAS,CAAEG,MAAM,IAE3Df,GACFgB,OAAOC,eAAeR,OAAQL,EAAc,CAC1Cc,cAAc,EACdC,YAAY,EACZX,IAAK,OACLY,IAAMC,IACJL,OAAOC,eAAeR,OAAQL,EAAc,CAC1Cc,cAAc,EACdC,YAAY,EACZG,UAAU,EACVD,UAEFhB,SAASkB,oBAAoB,mBAAoBX,GACjDD,UAqBca,GAChBC,EAAcC,EAClBjC,EACAgB,OAAOkB,SACPhC,GAAeiC,WACdC,OAAQC,GAAMA,EAAEC,MAAMC,OAIrB7B,GAAiBsB,GAAaQ,eAC1BvB,QAAQwB,IAAI,CAChB/B,MACIsB,GAAe,IAAIU,IAAI7C,MAAOwC,IAChC,MAAME,KAAEA,GAASF,EAAEC,MAEnB,GAAoB,mBAATC,EAAqB,CAC9B,MAAMI,QAAmBJ,IAErBI,GACFpB,OAAOqB,OAAOP,EAAEC,MAAO,IAClBK,EACHJ,UAAM9B,GAGZ,MAKN,MAAMoC,EAAY/B,QAAQC,IAAIC,OAAQ,+BAGlCV,GAAUuC,GAAWC,kBACvBhC,QAAQa,IAAIX,OAAQ,oCAAqCV,EAAOyC,OAGlE,MAAMC,EAAS7C,EAAaH,EAAyBE,GAC/C+C,EAAOrC,SAASsC,eAAe7C,GAC/B8C,QAAkBlD,IAAO,CAAEmD,UAAW7C,EAAayC,YAEnDK,EAAmB,IACvBC,EAAAC,cAACxD,EAAG,CAACyD,OAAQL,GACXG,EAAAC,cAACE,GAAeT,OAAQA,KAI5B,OAAKzC,GAA4C,MAA7B0C,EAAKS,QAAkB,SAIpCC,EAASC,YAAYX,EAAMK,EAAAC,cAACF,EAAY,OAHtCM,EAASE,WAAWZ,GAAMa,OAAOR,EAAAC,cAACF,EAAY,MAIzD"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{parse as e}from"devalue";const t=()=>{const t=window,r=t.__ssrBoostStream??=[],o=new Map;let s,c,n,i=!1,a=!1,l=!1;const m=new Promise((e,t)=>{c=e,n=t}),S=e=>{let t=o.get(e);if(!t){let r,s;const c=new Promise((e,t)=>{r=e,s=t});c.catch(()=>{}),t={promise:c,resolve:r,reject:s},o.set(e,t)}return t},d=t=>e(t,{SSRBPromise:([e])=>S(e).promise,SSRBObject:e=>Object.fromEntries(e),SSRBError:e=>{const t=Object.fromEntries(e),r=Object.assign(new Error("Streamed loader/action rejection"),t);return t.stack||delete r.stack,r},SSRBUndefined:()=>{}});return r.push=(...e)=>{for(const t of e)try{"shell"===t[0]?i=!0:"init"===t[0]?(s=d(t[1]),[,,a]=t,l=!0):S(t[1])[t[0]](d(t[2])),!l||a&&!i||c(s)}catch(e){n(e),o.forEach(t=>t.reject(e))}return 0},r.push(...r.splice(0)),m.catch(()=>{}),{ready:m}};export{t as default};
|
|
2
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sources":["../../src/browser/stream.ts"],"sourcesContent":[null],"names":["receiveStream","target","window","queue","__ssrBoostStream","promises","Map","state","resolveReady","rejectReady","hasShell","isEarly","isInitialized","ready","Promise","resolve","reject","deferred","id","pending","get","promise","res","rej","catch","set","value","payload","parse","SSRBPromise","SSRBObject","entries","Object","fromEntries","SSRBError","data","error","assign","Error","stack","SSRBUndefined","push","frames","frame","forEach","splice"],"mappings":"gCAUA,MAAMA,EAAgB,KACpB,MAAMC,EAASC,OACTC,EAASF,EAAOG,mBAAqB,GACrCC,EAAW,IAAIC,IACrB,IAGIC,EACAC,EACAC,EALAC,GAAW,EACXC,GAAU,EACVC,GAAgB,EAIpB,MAAMC,EAAQ,IAAIC,QAAiB,CAACC,EAASC,KAC3CR,EAAeO,EACfN,EAAcO,IAIVC,EAAYC,IAChB,IAAIC,EAAUd,EAASe,IAAIF,GAE3B,IAAKC,EAAS,CACZ,IAAIJ,EACAC,EACJ,MAAMK,EAAU,IAAIP,QAAQ,CAACQ,EAAKC,KAChCR,EAAUO,EACVN,EAASO,IAGNF,EAAQG,MAAM,QACnBL,EAAU,CAAEE,UAASN,UAASC,UAC9BX,EAASoB,IAAIP,EAAIC,EACnB,CAEA,OAAOA,GAIHO,EAASC,GACbC,EAAMD,EAAS,CACbE,YAAa,EAAEX,KAAkBD,EAASC,GAAIG,QAC9CS,WAAaC,GAAiCC,OAAOC,YAAYF,GACjEG,UAAYH,IACV,MAAMI,EAAOH,OAAOC,YAAYF,GAC1BK,EAAQJ,OAAOK,OAAO,IAAIC,MAAM,oCAAqCH,GAM3E,OAJKA,EAAKI,cACDH,EAAMG,MAGRH,GAETI,cAAe,SA+BnB,OA3BArC,EAAMsC,KAAO,IAAIC,KACf,IAAK,MAAMC,KAASD,EAClB,IACmB,UAAbC,EAAM,GACRjC,GAAW,EACW,SAAbiC,EAAM,IACfpC,EAAQmB,EAAMiB,EAAM,KACpB,CAAA,CAAKhC,GAAWgC,EAChB/B,GAAgB,GAEhBK,EAAS0B,EAAM,IAAIA,EAAM,IAAIjB,EAAMiB,EAAM,MAGvC/B,GAAmBD,IAAWD,GAChCF,EAAaD,EAEjB,CAAE,MAAO6B,GACP3B,EAAY2B,GACZ/B,EAASuC,QAASzB,GAAYA,EAAQH,OAAOoB,GAC/C,CAGF,OAAO,GAETjC,EAAMsC,QAAQtC,EAAM0C,OAAO,IACtBhC,EAAMW,MAAM,QAEV,CAAEX"}
|
package/core/compose-html.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
declare const composeHtml: (header: string, body: ReadableStream<Uint8Array>, footer: string, abort?: (reason?: unknown) => void, onComplete?: () => void) => ReadableStream<Uint8Array>;
|
|
1
|
+
import type DataStream from './data-stream.js';
|
|
2
|
+
/** Stream shell, data frames, React bytes and footer only under downstream demand. */
|
|
3
|
+
declare const composeHtml: (header: string, body: ReadableStream<Uint8Array>, footer: string, abort?: (reason?: unknown) => void, onComplete?: () => void, data?: DataStream) => ReadableStream<Uint8Array>;
|
|
5
4
|
export default composeHtml;
|
package/core/compose-html.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const
|
|
1
|
+
import e from"./html-boundary.js";const n=(n,t,a,r,o,c)=>{const i=new TextEncoder,d=t.getReader();let u,l="header",f=!1,s=!1;const h=e();let y,v=!0;const w=()=>{s||(s=!0,d.releaseLock())};return new ReadableStream({cancel:async e=>{f=!0,r?.(e),c?.cancel();try{s||await d.cancel(e)}finally{w(),o?.()}},async pull(e){try{if("header"===l&&(l="body",n))return void e.enqueue(i.encode(n));for(;!f;){const n=v?c?.take():void 0;if(f)return;if(n)return void e.enqueue(i.encode(n));if(y)return v=h(y),e.enqueue(y),void(y=void 0);if("body"===l){u??=d.read();const e=await(c&&!c.isDone&&v?Promise.race([u,c.changed().then(()=>{})]):u);if(f)return;if(!e)continue;if(u=void 0,!e.done){y=e.value;continue}l="footer",v=!0,w();continue}!c||c.isDone?(a&&e.enqueue(i.encode(a)),f=!0,o?.(),e.close()):await c.changed()}}catch(n){if(f)return;f=!0,r?.(n),c?.cancel(),e.error(n);try{s||await d.cancel(n).catch(()=>{})}finally{w(),o?.()}}}},{highWaterMark:0})};export{n as default};
|
|
2
2
|
//# sourceMappingURL=compose-html.js.map
|
package/core/compose-html.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose-html.js","sources":["../../src/core/compose-html.ts"],"sourcesContent":[null],"names":["composeHtml","header","body","footer","abort","onComplete","encoder","TextEncoder","reader","getReader","phase","ReadableStream","cancel","async","reason","
|
|
1
|
+
{"version":3,"file":"compose-html.js","sources":["../../src/core/compose-html.ts"],"sourcesContent":[null],"names":["composeHtml","header","body","footer","abort","onComplete","data","encoder","TextEncoder","reader","getReader","pendingRead","phase","isStopped","isReleased","observe","htmlBoundary","heldChunk","canInject","release","releaseLock","ReadableStream","cancel","async","reason","pull","controller","enqueue","encode","frames","take","undefined","read","chunk","isDone","Promise","race","changed","then","done","value","close","error","catch","highWaterMark"],"mappings":"kCAIA,MAAMA,EAAc,CAClBC,EACAC,EACAC,EACAC,EACAC,EACAC,KAEA,MAAMC,EAAU,IAAIC,YACdC,EAASP,EAAKQ,YACpB,IAGIC,EAHAC,EAAsC,SACtCC,GAAY,EACZC,GAAa,EAEjB,MAAMC,EAAUC,IAChB,IACIC,EADAC,GAAY,EAIhB,MAAMC,EAAU,KACTL,IACHA,GAAa,EACbL,EAAOW,gBAIX,OAAO,IAAIC,eACT,CAEEC,OAAQC,MAAOC,IACbX,GAAY,EACZT,IAAQoB,GACRlB,GAAMgB,SAEN,IACOR,SACGL,EAAOa,OAAOE,EAExB,SACEL,IACAd,KACF,GAIF,UAAMoB,CAAKC,GACT,IACE,GAAc,WAAVd,IACFA,EAAQ,OAEJX,GAGF,YAFAyB,EAAWC,QAAQpB,EAAQqB,OAAO3B,IAMtC,MAAQY,GAAW,CACjB,MAAMgB,EAASX,EAAYZ,GAAMwB,YAASC,EAE1C,GAAIlB,EACF,OAGF,GAAIgB,EAGF,YAFAH,EAAWC,QAAQpB,EAAQqB,OAAOC,IAKpC,GAAIZ,EAKF,OAJAC,EAAYH,EAAQE,GACpBS,EAAWC,QAAQV,QACnBA,OAAYc,GAKd,GAAc,SAAVnB,EAAkB,CACpBD,IAAgBF,EAAOuB,OACvB,MAAMC,QAAe3B,IAASA,EAAK4B,QAAUhB,EACzCiB,QAAQC,KAAK,CAACzB,EAAaL,EAAK+B,UAAUC,KAAK,UAC/C3B,GAEJ,GAAIE,EACF,OAGF,IAAKoB,EACH,SAKF,GAFAtB,OAAcoB,GAETE,EAAMM,KAAM,CACftB,EAAYgB,EAAMO,MAElB,QACF,CAEA5B,EAAQ,SACRM,GAAY,EACZC,IACA,QACF,EAEIb,GAASA,EAAK4B,QAKd/B,GACFuB,EAAWC,QAAQpB,EAAQqB,OAAOzB,IAGpCU,GAAY,EACZR,MACAqB,EAAWe,eAVHnC,EAAK+B,SAWf,CACF,CAAE,MAAOK,GACP,GAAI7B,EACF,OAGFA,GAAY,EACZT,IAAQsC,GACRpC,GAAMgB,SACNI,EAAWgB,MAAMA,GAEjB,IACO5B,SACGL,EAAOa,OAAOoB,GAAOC,MAAM,OAErC,SACExB,IACAd,KACF,CACF,CACF,GAEF,CAAEuC,cAAe"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { StaticHandlerContext } from 'react-router';
|
|
2
|
+
import type Diagnostics from '../services/diagnostics.js';
|
|
3
|
+
interface IPending {
|
|
4
|
+
settled: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Preserve route response details without shipping arbitrary error properties. */
|
|
7
|
+
declare const errorProperties: (reason: unknown, diagnostics: boolean) => Record<string, unknown>;
|
|
8
|
+
/**
|
|
9
|
+
* Request-local promise identities and settlements. devalue encodes each frame's
|
|
10
|
+
* value; promise reducers keep settlement scheduling outside the value codec.
|
|
11
|
+
* No React bytes are read here. Nested settlements can introduce further placeholders.
|
|
12
|
+
*/
|
|
13
|
+
declare class DataStream {
|
|
14
|
+
protected readonly diagnostics?: Diagnostics | undefined;
|
|
15
|
+
protected readonly nonce?: string | undefined;
|
|
16
|
+
readonly initial: string;
|
|
17
|
+
readonly done: Promise<void>;
|
|
18
|
+
protected resolveDone: () => void;
|
|
19
|
+
protected notify?: () => void;
|
|
20
|
+
protected change?: Promise<void>;
|
|
21
|
+
protected readonly identities: WeakMap<Promise<unknown>, number>;
|
|
22
|
+
protected readonly pending: Map<number, IPending>;
|
|
23
|
+
protected readonly frames: string[];
|
|
24
|
+
protected initialized: boolean;
|
|
25
|
+
protected stopped: boolean;
|
|
26
|
+
protected aborted: boolean;
|
|
27
|
+
protected nextId: number;
|
|
28
|
+
constructor(context: StaticHandlerContext, diagnostics?: Diagnostics | undefined, nonce?: string | undefined);
|
|
29
|
+
/** Use the codec's public plugin API, without depending on React Router internals. */
|
|
30
|
+
protected promiseId: (value: unknown) => [number] | false;
|
|
31
|
+
/** Encode one complete value, preserving the codec's built-in value representations. */
|
|
32
|
+
protected encodeValue(value: unknown): string;
|
|
33
|
+
/** Publish only once, and finish encoding before announcing a settlement. */
|
|
34
|
+
protected settle(id: number, value: unknown, rejected: boolean): void;
|
|
35
|
+
/** Notify a waiting pull and settle completion only after nested values were visited. */
|
|
36
|
+
protected wake(): void;
|
|
37
|
+
get isDone(): boolean;
|
|
38
|
+
/** Wait for data, without starting a read from the React stream. */
|
|
39
|
+
changed(): Promise<void>;
|
|
40
|
+
/** Drain completed value frames before delivering a React boundary chunk. */
|
|
41
|
+
take(): string;
|
|
42
|
+
/** Publish initialization in the selected shell/footer block to unblock hydration. */
|
|
43
|
+
state(isEarly: boolean): string;
|
|
44
|
+
/** Reject outstanding placeholders before a timeout closes the HTML response. */
|
|
45
|
+
abort(): void;
|
|
46
|
+
/** A disconnected client cannot receive scripts; detach request state from late work. */
|
|
47
|
+
cancel(): void;
|
|
48
|
+
}
|
|
49
|
+
export { errorProperties };
|
|
50
|
+
export default DataStream;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{stringify as t}from"devalue";import{isRouteErrorResponse as e}from"react-router";import i,{streamScript as s}from"./script.js";import o from"../helpers/serialize-errors.js";const r=(t,i)=>{const s=t,o=e(t),r="DataWithResponseInit"===s?.type,n=o?t.status:s?.init?.status,a=o?t.statusText:s?.init?.statusText,c={message:s?.message??(o||r?a||`Route data error (${n??500})`:String(t)),name:s?.name??"Error"};return(o||r)&&Object.assign(c,{status:n??500,statusText:a??"",data:s?.data,internal:!1}),i&&s?.stack&&(c.stack=s.stack),c};class n{diagnostics;nonce;initial;done;resolveDone;notify;change;identities=new WeakMap;pending=new Map;frames=[];initialized=!1;stopped=!1;aborted=!1;nextId=0;constructor(t,e,i){this.diagnostics=e,this.nonce=i,e?.inspectRouterState(t),this.done=new Promise(t=>{this.resolveDone=t});try{this.initial=this.encodeValue({loaderData:t.loaderData,actionData:t.actionData,errors:o(t.errors)}),this.initialized=!0,this.wake()}catch(t){throw this.cancel(),t}}promiseId=t=>{if(t instanceof Promise){let e=this.identities.get(t);if(void 0===e){e=this.nextId++,this.identities.set(t,e),this.pending.set(e,{settled:!1});const i=e;t.then(t=>this.settle(i,t,!1),t=>this.settle(i,t,!0)),this.aborted&&this.settle(e,new Error("SSR loader/action promise aborted before it settled."),!0)}return[e]}return!1};encodeValue(i){return t(i,{SSRBPromise:this.promiseId,SSRBError:t=>(t instanceof Error||e(t))&&Object.entries(r(t,Boolean(this.diagnostics))),SSRBObject:t=>Boolean(t&&"object"==typeof t&&Object.hasOwn(t,"__proto__"))&&Object.entries(t),SSRBUndefined:t=>"function"==typeof t||"symbol"==typeof t||Boolean(t&&"object"==typeof t&&!Array.isArray(t)&&![Object.prototype,null,Date.prototype,Map.prototype,Set.prototype,RegExp.prototype,Promise.prototype,Error.prototype].includes(Object.getPrototypeOf(t)))})}settle(t,e,i){const o=this.pending.get(t);if(o&&!o.settled&&!this.stopped){o.settled=!0,i||this.diagnostics?.inspectStreamValue(e,t);try{const o=this.encodeValue(i?Object.assign(new Error("Streamed loader/action rejection"),r(e,Boolean(this.diagnostics))):e);this.frames.push(s([i?"reject":"resolve",t,o],this.nonce))}catch(e){const i=this.encodeValue(new Error(`Cannot serialize streamed value: ${String(e)}`));this.frames.push(s(["reject",t,i],this.nonce))}finally{this.pending.delete(t),this.wake()}}}wake(){this.notify?.(),this.notify=void 0,this.change=void 0,this.initialized&&!this.pending.size&&this.resolveDone()}get isDone(){return this.initialized&&!this.pending.size}changed(){return this.frames.length||this.isDone?Promise.resolve():this.change??=new Promise(t=>{this.notify=t})}take(){return this.frames.splice(0).join("")}state(t){const{initial:e}=this;return i("window.__staticRouterHydrationData = {__ssrBoostStream: true};",this.nonce,!0)+s(["init",e,t],this.nonce)}abort(){this.aborted=!0;let t=0;for(const[e,i]of this.pending)i.settled||(t++,this.settle(e,new Error("SSR loader/action promise aborted before it settled."),!0));t&&this.diagnostics?.streamAborted(t)}cancel(){this.stopped=!0,this.initialized=!0,this.pending.clear(),this.frames.length=0,this.wake()}}export{n as default,r as errorProperties};
|
|
2
|
+
//# sourceMappingURL=data-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-stream.js","sources":["../../src/core/data-stream.ts"],"sourcesContent":[null],"names":["errorProperties","reason","diagnostics","value","isResponse","isRouteErrorResponse","isDataError","type","status","init","statusText","properties","message","String","name","Object","assign","data","internal","stack","DataStream","nonce","initial","done","resolveDone","notify","change","identities","WeakMap","pending","Map","frames","initialized","stopped","aborted","nextId","constructor","context","this","inspectRouterState","Promise","resolve","encodeValue","loaderData","actionData","errors","serializeErrors","wake","error","cancel","promiseId","id","get","undefined","set","settled","then","result","settle","Error","stringify","SSRBPromise","SSRBError","entries","Boolean","SSRBObject","item","hasOwn","SSRBUndefined","Array","isArray","prototype","Date","Set","RegExp","includes","getPrototypeOf","rejected","inspectStreamValue","payload","push","streamScript","delete","size","isDone","changed","length","take","splice","join","state","isEarly","script","abort","count","streamAborted","clear"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Track tag, comment and raw-text boundaries across arbitrary React byte chunks.
|
|
3
|
+
* Data scripts may be inserted only after a complete tag, never in a split token
|
|
4
|
+
* or script/style body. This observer neither buffers HTML nor reads ahead.
|
|
5
|
+
*/
|
|
6
|
+
declare const htmlBoundary: () => ((chunk: Uint8Array) => boolean);
|
|
7
|
+
export default htmlBoundary;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const t=()=>{let t="text",e="",r="",o="";return s=>{for(const n of s){const s=String.fromCharCode(n);"raw"===t?(e=(e+s).slice(-32),">"===s&&new RegExp(`</${o}\\s*>$`,"i").test(e)&&(t="text",e="",o="")):"comment"===t?(e=(e+s).slice(-3),"--\x3e"===e&&(t="text",e="")):"tag"===t?(e.length<32&&(e+=s),"\x3c!--"===e?t="comment":r?s===r&&(r=""):'"'===s||"'"===s?r=s:">"===s&&(o=/^<(script|style|textarea|title)(?:\s|>)/i.exec(e)?.[1]?.toLowerCase()??"",t=o?"raw":"text",e="")):"<"===s&&(t="tag",e="<")}return"text"===t&&62===s[s.length-1]}};export{t as default};
|
|
2
|
+
//# sourceMappingURL=html-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-boundary.js","sources":["../../src/core/html-boundary.ts"],"sourcesContent":[null],"names":["htmlBoundary","mode","token","quote","raw","chunk","byte","char","String","fromCharCode","slice","RegExp","test","length","exec","toLowerCase"],"mappings":"AAKA,MAAMA,EAAe,KACnB,IAAIC,EAA2C,OAC3CC,EAAQ,GACRC,EAAQ,GACRC,EAAM,GAEV,OAAQC,IACN,IAAK,MAAMC,KAAQD,EAAO,CACxB,MAAME,EAAOC,OAAOC,aAAaH,GAEpB,QAATL,GACFC,GAASA,EAAQK,GAAMG,OAAM,IAEhB,MAATH,GAAgB,IAAII,OAAO,KAAKP,UAAa,KAAKQ,KAAKV,KACzDD,EAAO,OACPC,EAAQ,GACRE,EAAM,KAEU,YAATH,GACTC,GAASA,EAAQK,GAAMG,OAAM,GAEf,WAAVR,IACFD,EAAO,OACPC,EAAQ,KAEQ,QAATD,GACLC,EAAMW,OAAS,KACjBX,GAASK,GAGG,YAAVL,EACFD,EAAO,UACEE,EACLI,IAASJ,IACXA,EAAQ,IAEQ,MAATI,GAAyB,MAATA,EACzBJ,EAAQI,EACU,MAATA,IACTH,EAAM,2CAA2CU,KAAKZ,KAAS,IAAIa,eAAiB,GACpFd,EAAOG,EAAM,MAAQ,OACrBF,EAAQ,KAEQ,MAATK,IACTN,EAAO,MACPC,EAAQ,IAEZ,CAEA,MAAgB,SAATD,GAA+C,KAA5BI,EAAMA,EAAMQ,OAAS"}
|
package/core/render.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export interface ISsrRequestContext<TAppProps = Record<string, any>> {
|
|
|
29
29
|
serverContext?: IServerContext;
|
|
30
30
|
}
|
|
31
31
|
export interface IRenderStreamOptions {
|
|
32
|
+
nonce?: string;
|
|
33
|
+
bootstrapScriptContent?: string;
|
|
32
34
|
onError: (error: unknown) => void;
|
|
33
35
|
signal: AbortSignal;
|
|
34
36
|
}
|
|
@@ -58,6 +60,10 @@ export interface ICoreRenderParams<TAppProps = Record<string, any>> {
|
|
|
58
60
|
renderToStream: TRenderToStream;
|
|
59
61
|
}
|
|
60
62
|
export interface ICoreRenderOptions<TAppProps = Record<string, any>> {
|
|
63
|
+
/** Hydrate the parsed shell while deferred boundaries are still pending. */
|
|
64
|
+
hydration?: 'early' | 'footer';
|
|
65
|
+
nonce?: string;
|
|
66
|
+
bootstrapScriptContent?: string;
|
|
61
67
|
/**
|
|
62
68
|
* React rendering deadline in milliseconds, starting after router preparation.
|
|
63
69
|
*/
|
|
@@ -100,5 +106,5 @@ export interface ICoreRenderOptions<TAppProps = Record<string, any>> {
|
|
|
100
106
|
/**
|
|
101
107
|
* Coordinate router queries, React rendering and the final Fetch response.
|
|
102
108
|
*/
|
|
103
|
-
declare const render: <TAppProps>({ createApp, handler, renderToStream }: ICoreRenderParams<TAppProps>, context: ISsrRequestContext<TAppProps>, { abortDelay, getState, onError, onResponse, onRouterReady, onShellError, onShellReady, prepare, routerRequestContext, }: ICoreRenderOptions<TAppProps>, executionContext?: ISsrExecutionContext) => Promise<Response>;
|
|
109
|
+
declare const render: <TAppProps>({ createApp, handler, renderToStream }: ICoreRenderParams<TAppProps>, context: ISsrRequestContext<TAppProps>, { abortDelay, getState, hydration, nonce, bootstrapScriptContent, onError, onResponse, onRouterReady, onShellError, onShellReady, prepare, routerRequestContext, }: ICoreRenderOptions<TAppProps>, executionContext?: ISsrExecutionContext) => Promise<Response>;
|
|
104
110
|
export default render;
|
package/core/render.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"react";import{createStaticRouter as t,StaticRouterProvider as r}from"react-router";import
|
|
1
|
+
import e from"react";import{createStaticRouter as t,StaticRouterProvider as r}from"react-router";import o from"../constants/stream-error.js";import{ServerProvider as s}from"../context/server.js";import n from"./compose-html.js";import a from"./data-stream.js";import c from"./head-response.js";import{mergeResponseHeaders as d}from"./headers.js";import i from"./transform-html.js";import l from"../helpers/build-custom-state.js";import m from"../helpers/obtain-stream-error.js";const u="text/html",h="Content-Type",p=async({createApp:p,handler:x,renderToStream:f},w,{abortDelay:y=15e3,getState:R,hydration:S="footer",nonce:C,bootstrapScriptContent:E,onError:b,onResponse:g,onRouterReady:q,onShellError:v,onShellReady:j,prepare:T,routerRequestContext:A},B)=>{const H=await x.query(w.request,{requestContext:A??w});if(H instanceof Response)return c(w.request,d(H,w.response.headers));w.routerContext=H;const _=new a(H,w.diagnostics,C);try{await(T?.({context:w,executionContext:B}))}catch(e){throw _.cancel(),e}const{isStream:D=!0}=await(q?.({context:w}))??{};w.isStream=D,w.serverContext={basename:w.routerContext.basename,isServer:!0,response:null};const L=t(x.dataRoutes,w.routerContext),k=e.createElement(s,{context:w.serverContext},p(e.createElement(r,{router:L,context:w.routerContext,hydrate:!1}),w)),P=new AbortController;let I,$,z=!1;const F=()=>K(w.request.signal.reason),G=()=>clearTimeout(M),J=()=>{G(),w.request.signal.removeEventListener("abort",F)},K=e=>{z||(z=!0,I=e,J(),w.didError??=o.RenderCancel,_.abort(),P.abort(e),$?.abort(e))},M=setTimeout(()=>{w.didError=o.RenderTimeout,K()},y);w.request.signal.aborted?K(w.request.signal.reason):w.request.signal.addEventListener("abort",F,{once:!0});try{$=await f(k,{nonce:C,bootstrapScriptContent:"early"===S&&D?`(window.__ssrBoostStream = window.__ssrBoostStream || []).push(["shell"]);${E??""};document.currentScript?.remove();`:E,onError:e=>{const t=m(e);!z||t.code!==o.RenderAborted&&e!==P.signal.reason||(t.code=w.didError===o.RenderTimeout?o.RenderTimeout:o.RenderCancel);const{code:r}=t;w.didError??=r,b?.({context:w,error:t})},signal:P.signal}),z&&$.abort(I),Promise.all([$.allReady,_.done]).then(G,G),await(D?$.shellReady:Promise.all([$.allReady,_.done]))}catch(e){return K(e),await($?.stream.cancel(e).catch(()=>{})),((e,t,r)=>{const o=t instanceof Error?t:new Error(String(t)),s=r?.({context:e,error:o})||"<!doctype html><p>Internal Server Error</p>",n=new Headers(e.response.headers);return n.set(h,u),new Response("HEAD"===e.request.method?null:s,{headers:n,status:500})})(w,e,v)}try{const e=w.serverContext.response;if(e&&(N=e,Boolean(N&&N.status>=300&&N.status<400&&N.headers.has("Location"))))return K(),await $.stream.cancel().catch(()=>{}),c(w.request,d(e,w.response.headers));const{header:t,footer:r,headers:o,status:s}=((e,{getState:t,onShellReady:r,hydration:o,nonce:s},n)=>{const a=e.serverContext.response;e.response.status=a?.status??e.response.status??e.routerContext.statusCode??200,e.response.headers.has(h)||e.response.headers.set(h,u);const c=r?.({context:e})??{},d="early"===o&&e.isStream,i=l(t?.({context:e}),e.diagnostics,s,Boolean(d));let m=c.header||e.html.header;const p=c.footer||e.html.footer;e.diagnostics?.inspectShell({header:m,footer:p});let x=p;return d?m+=i+n.state(!0):x=i+n.state(!1)+n.take()+x,{header:m,footer:x,headers:new Headers(e.response.headers),status:e.response.status}})(w,{getState:R,onShellReady:j,hydration:S,nonce:C},_);if("HEAD"===w.request.method||[204,205,304].includes(s))return K(),await $.stream.cancel().catch(()=>{}),new Response(null,{headers:o,status:s});const a=n(t,$.stream,r,K,J,_),m=i(a,g?(e,t)=>g({context:w,html:e,isEnd:t}):void 0,w.diagnostics);return $.start(),new Response(m,{headers:o,status:s})}catch(e){throw K(e),$.stream.locked||await $.stream.cancel(e).catch(()=>{}),e}var N};export{p as default};
|
|
2
2
|
//# sourceMappingURL=render.js.map
|
package/core/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sources":["../../src/core/render.tsx"],"sourcesContent":[null],"names":["HTML_CONTENT_TYPE","CONTENT_TYPE","render","async","createApp","handler","renderToStream","context","abortDelay","getState","onError","onResponse","onRouterReady","onShellError","onShellReady","prepare","routerRequestContext","executionContext","queried","query","request","requestContext","Response","headResponse","mergeResponseHeaders","response","headers","routerContext","isStream","serverContext","basename","isServer","router","createStaticRouter","dataRoutes","node","React","createElement","ServerProvider","StaticRouterProvider","hydrate","renderController","AbortController","abortReason","output","hasAborted","onRequestAbort","abort","signal","reason","clearAbortTimer","clearTimeout","abortTimer","cleanup","removeEventListener","didError","StreamError","RenderCancel","setTimeout","RenderTimeout","aborted","addEventListener","once","
|
|
1
|
+
{"version":3,"file":"render.js","sources":["../../src/core/render.tsx"],"sourcesContent":[null],"names":["HTML_CONTENT_TYPE","CONTENT_TYPE","render","async","createApp","handler","renderToStream","context","abortDelay","getState","hydration","nonce","bootstrapScriptContent","onError","onResponse","onRouterReady","onShellError","onShellReady","prepare","routerRequestContext","executionContext","queried","query","request","requestContext","Response","headResponse","mergeResponseHeaders","response","headers","routerContext","dataStream","DataStream","diagnostics","error","cancel","isStream","serverContext","basename","isServer","router","createStaticRouter","dataRoutes","node","React","createElement","ServerProvider","StaticRouterProvider","hydrate","renderController","AbortController","abortReason","output","hasAborted","onRequestAbort","abort","signal","reason","clearAbortTimer","clearTimeout","abortTimer","cleanup","removeEventListener","didError","StreamError","RenderCancel","setTimeout","RenderTimeout","aborted","addEventListener","once","streamError","obtainStreamError","code","RenderAborted","Promise","all","allReady","done","then","shellReady","stream","catch","shellError","Error","String","html","Headers","set","method","status","createShellErrorResponse","serverResponse","Boolean","has","header","footer","statusCode","shell","isEarly","customState","buildCustomState","shellFooter","inspectShell","state","take","prepareHtmlResponse","includes","body","composeHtml","transformed","transformHtml","isEnd","undefined","start","locked"],"mappings":"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"}
|
package/core/script.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Escape an attribute independently of the JavaScript string escaping rules. */
|
|
2
|
+
declare const script: (content: string, nonce?: string, isTemporary?: boolean) => string;
|
|
3
|
+
/** Queue frames even when the async browser entry has not executed yet. */
|
|
4
|
+
declare const streamScript: (frame: unknown, nonce?: string) => string;
|
|
5
|
+
export { streamScript };
|
|
6
|
+
export default script;
|
package/core/script.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import r from"../helpers/html-escape.js";const e=(r,e,s=!1)=>`<script async${void 0===e?"":` nonce="${e.replace(/[&<>"']/g,r=>`&#${r.charCodeAt(0)};`)}"`}>${r}${s?"document.currentScript?.remove();":""}<\/script>`,s=(s,t)=>e(`(window.__ssrBoostStream = window.__ssrBoostStream || []).push(${r(JSON.stringify(s))});`,t,!0);export{e as default,s as streamScript};
|
|
2
|
+
//# sourceMappingURL=script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.js","sources":["../../src/core/script.ts"],"sourcesContent":[null],"names":["script","content","nonce","isTemporary","undefined","replace","char","charCodeAt","streamScript","frame","htmlEscape","JSON","stringify"],"mappings":"yCAGA,MAAMA,EAAS,CAACC,EAAiBC,EAAgBC,GAAc,IAMtD,qBAJKC,IAAVF,EACI,GACA,WAAWA,EAAMG,QAAQ,WAAaC,GAAS,KAAKA,EAAKC,WAAW,aAEtCN,IAAUE,EAAc,oCAAsC,eAI9FK,EAAe,CAACC,EAAgBP,IACpCF,EACE,kEAAkEU,EAAWC,KAAKC,UAAUH,QAC5FP,GACA"}
|
package/edge/render-to-stream.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import*as e from"react-dom/server";const r=async()=>e.renderToReadableStream??(await(import("react-dom/server.browser"))).renderToReadableStream,
|
|
1
|
+
import*as e from"react-dom/server";const r=async()=>e.renderToReadableStream??(await(import("react-dom/server.browser"))).renderToReadableStream,t=async(e,{onError:t,signal:a,nonce:o,bootstrapScriptContent:n})=>{const s=new AbortController;let l;const c=new Promise((e,r)=>{l=r}),i=()=>{const{reason:e}=a;s.abort(e);const{reason:r}=s.signal;l(r instanceof Error?r:new Error(String(r)))};let d;a.aborted?i():a.addEventListener("abort",i,{once:!0});try{d=await Promise.race([r().then(r=>r(e,{onError:t,signal:s.signal,nonce:o,bootstrapScriptContent:n})),c])}catch(e){a.removeEventListener("abort",i);const r=Promise.reject(e);return r.catch(()=>{}),{allReady:r,abort:e=>s.abort(e),shellReady:r,start:()=>{},stream:new ReadableStream}}const b=()=>a.removeEventListener("abort",i);return d.allReady.then(b,b),{allReady:d.allReady,abort:e=>s.abort(e),shellReady:Promise.resolve(),start:()=>{},stream:d}};export{t as default};
|
|
2
2
|
//# sourceMappingURL=render-to-stream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-to-stream.js","sources":["../../src/edge/render-to-stream.ts"],"sourcesContent":[null],"names":["getRenderer","async","ReactDOMServer","renderToReadableStream","renderToStream","node","onError","signal","controller","AbortController","rejectPending","pendingAbort","Promise","_","reject","abort","reason","signalReason","Error","String","stream","aborted","addEventListener","once","race","then","error","removeEventListener","shellError","catch","allReady","shellReady","start","ReadableStream","removeAbortListener","resolve"],"mappings":"mCAMA,MAAMA,EAAcC,SAClBC,EAAeC,sCACD,8BAA6BA,uBAKvCC,EAAkCH,
|
|
1
|
+
{"version":3,"file":"render-to-stream.js","sources":["../../src/edge/render-to-stream.ts"],"sourcesContent":[null],"names":["getRenderer","async","ReactDOMServer","renderToReadableStream","renderToStream","node","onError","signal","nonce","bootstrapScriptContent","controller","AbortController","rejectPending","pendingAbort","Promise","_","reject","abort","reason","signalReason","Error","String","stream","aborted","addEventListener","once","race","then","error","removeEventListener","shellError","catch","allReady","shellReady","start","ReadableStream","removeAbortListener","resolve"],"mappings":"mCAMA,MAAMA,EAAcC,SAClBC,EAAeC,sCACD,8BAA6BA,uBAKvCC,EAAkCH,MACtCI,GACEC,UAASC,SAAQC,QAAOC,6BAE1B,MAAMC,EAAa,IAAIC,gBACvB,IAAIC,EAKJ,MAAMC,EAAe,IAAIC,QAAe,CAACC,EAAGC,KAC1CJ,EAAgBI,IAMZC,EAAQ,KACZ,MAAQC,OAAQC,GAAiBZ,EAEjCG,EAAWO,MAAME,GAEjB,MAAMD,OAAEA,GAAWR,EAAWH,OAE9BK,EAAcM,aAAkBE,MAAQF,EAAS,IAAIE,MAAMC,OAAOH,MASpE,IAAII,EANAf,EAAOgB,QACTN,IAEAV,EAAOiB,iBAAiB,QAASP,EAAO,CAAEQ,MAAM,IAKlD,IACEH,QAAeR,QAAQY,KAAK,CAC1B1B,IAAc2B,KAAMxB,GAClBA,EAAuBE,EAAM,CAC3BC,UACAC,OAAQG,EAAWH,OACnBC,QACAC,4BAGJI,GAEJ,CAAE,MAAOe,GACPrB,EAAOsB,oBAAoB,QAASZ,GACpC,MAAMa,EAAahB,QAAQE,OAAOY,GAIlC,OAFKE,EAAWC,MAAM,QAEf,CACLC,SAAUF,EAKVb,MAAQC,GAAWR,EAAWO,MAAMC,GACpCe,WAAYH,EAKZI,MAAO,OACPZ,OAAQ,IAAIa,eAEhB,CAKA,MAAMC,EAAsB,IAAY7B,EAAOsB,oBAAoB,QAASZ,GAI5E,OAFKK,EAAOU,SAASL,KAAKS,EAAqBA,GAExC,CACLJ,SAAUV,EAAOU,SAKjBf,MAAQC,GAAWR,EAAWO,MAAMC,GACpCe,WAAYnB,QAAQuB,UAKpBH,MAAO,OACPZ"}
|
|
@@ -2,5 +2,5 @@ import type Diagnostics from '../services/diagnostics.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Build custom state
|
|
4
4
|
*/
|
|
5
|
-
declare function buildCustomState(initState?: Record<string, Record<string, any>> | void, diagnostics?: Diagnostics): string;
|
|
5
|
+
declare function buildCustomState(initState?: Record<string, Record<string, any>> | void, diagnostics?: Diagnostics, nonce?: string, isTemporary?: boolean): string;
|
|
6
6
|
export default buildCustomState;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import t from"./html-escape.js";function e(e,
|
|
1
|
+
import t from"../core/script.js";import r from"./html-escape.js";function e(e,i,n,s=!1){i?.inspectState(e);return Object.entries(e??{}).map(([e,i])=>{if(!e||!i||!Object.keys(i||{}).length)return"";const o=r(JSON.stringify(JSON.stringify(i))),c=/^[A-Za-z_$][\w$]*$/.test(e)?`.${e}`:`[${r(JSON.stringify(e))}]`;return t(`window${c} = JSON.parse(${o});`,n,s)}).join("").trim()}export{e as default};
|
|
2
2
|
//# sourceMappingURL=build-custom-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-custom-state.js","sources":["../../src/helpers/build-custom-state.ts"],"sourcesContent":[null],"names":["buildCustomState","initState","diagnostics","inspectState","Object","entries","map","key","state","keys","length","json","htmlEscape","JSON","stringify","test","join","trim"],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-custom-state.js","sources":["../../src/helpers/build-custom-state.ts"],"sourcesContent":[null],"names":["buildCustomState","initState","diagnostics","nonce","isTemporary","inspectState","Object","entries","map","key","state","keys","length","json","htmlEscape","JSON","stringify","property","test","script","join","trim"],"mappings":"iEAOA,SAASA,EACPC,EACAC,EACAC,EACAC,GAAc,GAEdF,GAAaG,aAAaJ,GAe1B,OAbqBK,OAAOC,QAAQN,GAAa,CAAA,GAAIO,IAAI,EAAEC,EAAKC,MAC9D,IAAKD,IAAQC,IAAUJ,OAAOK,KAAKD,GAAS,IAAIE,OAC9C,MAAO,GAGT,MAAMC,EAAOC,EAAWC,KAAKC,UAAUD,KAAKC,UAAUN,KAChDO,EAAW,qBAAqBC,KAAKT,GACvC,IAAIA,IACJ,IAAIK,EAAWC,KAAKC,UAAUP,OAElC,OAAOU,EAAO,SAASF,kBAAyBJ,MAAUV,EAAOC,KAG/CgB,KAAK,IAAIC,MAC/B"}
|
|
@@ -3,5 +3,5 @@ import type Diagnostics from '../services/diagnostics.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Build router state
|
|
5
5
|
*/
|
|
6
|
-
declare function buildRouterState(context: StaticHandlerContext, diagnostics?: Diagnostics): string;
|
|
6
|
+
declare function buildRouterState(context: StaticHandlerContext, diagnostics?: Diagnostics, nonce?: string): string;
|
|
7
7
|
export default buildRouterState;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import r from"./html-escape.js";import
|
|
1
|
+
import r from"../core/script.js";import t from"./html-escape.js";import a from"./serialize-errors.js";function o(o,e,i){e?.inspectRouterState(o);const{loaderData:s,actionData:n,errors:c}=o,p={loaderData:s,actionData:n,errors:a(c)},f=t(JSON.stringify(JSON.stringify(p)));return r(`window.__staticRouterHydrationData = JSON.parse(${f});`,i)}export{o as default};
|
|
2
2
|
//# sourceMappingURL=build-router-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-router-state.js","sources":["../../src/helpers/build-router-state.ts"],"sourcesContent":[null],"names":["buildRouterState","context","diagnostics","inspectRouterState","loaderData","actionData","errors","routerState","serializeErrors","htmlEscape","JSON","stringify"],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-router-state.js","sources":["../../src/helpers/build-router-state.ts"],"sourcesContent":[null],"names":["buildRouterState","context","diagnostics","nonce","inspectRouterState","loaderData","actionData","errors","routerState","serializeErrors","json","htmlEscape","JSON","stringify","script"],"mappings":"sGASA,SAASA,EACPC,EACAC,EACAC,GAEAD,GAAaE,mBAAmBH,GAEhC,MAAMI,WAAEA,EAAUC,WAAEA,EAAUC,OAAEA,GAAWN,EACrCO,EAAc,CAClBH,aACAC,aACAC,OAAQE,EAAgBF,IAEpBG,EAAOC,EAAWC,KAAKC,UAAUD,KAAKC,UAAUL,KAEtD,OAAOM,EAAO,mDAAmDJ,MAAUP,EAC7E"}
|
package/node/render-to-stream.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{PassThrough as r,Readable as e}from"node:stream";import{renderToPipeableStream as t}from"react-dom/server";const o=(o,n)=>{const a=new r,s=e.toWeb(a,{strategy:{highWaterMark:a.readableHighWaterMark,size:r=>r.byteLength}});let i,l,c,d;const
|
|
1
|
+
import{PassThrough as r,Readable as e}from"node:stream";import{renderToPipeableStream as t}from"react-dom/server";const o=(o,n)=>{const a=new r,s=e.toWeb(a,{strategy:{highWaterMark:a.readableHighWaterMark,size:r=>r.byteLength}});let i,l,c,d;const b=new Promise((r,e)=>{i=e,c=r}),g=new Promise((r,e)=>{l=e,d=r});b.catch(()=>{}),g.catch(()=>{});let h=!1,m=!1;const p=t(o,{nonce:n.nonce,bootstrapScriptContent:n.bootstrapScriptContent,onAllReady:c,onError:n.onError,onShellError:r=>{const e=r instanceof Error?r:new Error(String(r));h=!0,i(e),l(e)},onShellReady:()=>{h=!0,d()}}),E=r=>{if(!m){if(m=!0,!h){h=!0;const e=r instanceof Error?r:new Error("string"==typeof r?r:"Render aborted");l(e),i(e)}p.abort(r)}},f=()=>E(n.signal.reason),y=()=>n.signal.removeEventListener("abort",f);n.signal.aborted?f():n.signal.addEventListener("abort",f,{once:!0}),b.then(y,y);let w=!1;return{allReady:b,abort:E,shellReady:g,start:()=>{w||(w=!0,p.pipe(a))},stream:s}};export{o as default};
|
|
2
2
|
//# sourceMappingURL=render-to-stream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-to-stream.js","sources":["../../src/node/render-to-stream.ts"],"sourcesContent":[null],"names":["renderToStream","node","options","destination","PassThrough","stream","Readable","toWeb","strategy","highWaterMark","readableHighWaterMark","size","chunk","byteLength","rejectAll","rejectShell","resolveAll","resolveShell","allReady","Promise","resolve","reject","shellReady","catch","hasShellSettled","hasAborted","rendered","renderToPipeableStream","onAllReady","onError","onShellError","error","shellError","Error","String","onShellReady","abort","reason","onAbort","signal","cleanup","removeEventListener","aborted","addEventListener","once","then","hasStarted","start","pipe"],"mappings":"kHAOA,MAAMA,EAAkC,CAACC,EAAMC,KAC7C,MAAMC,EAAc,IAAIC,EAClBC,EAASC,EAASC,MAAMJ,EAAa,CACzCK,SAAU,CACRC,cAAeN,EAAYO,sBAK3BC,KAAOC,GAAsBA,EAAMC,cAGvC,IAAIC,EACAC,EACAC,EACAC,EAKJ,MAAMC,EAAW,IAAIC,QAAc,CAACC,EAASC,KAC3CP,EAAYO,EACZL,EAAaI,IAMTE,EAAa,IAAIH,QAAc,CAACC,EAASC,KAC7CN,EAAcM,EACdJ,EAAeG,IAGZF,EAASK,MAAM,QACfD,EAAWC,MAAM,QAEtB,IAAIC,GAAkB,EAClBC,GAAa,EACjB,MAAMC,EAAWC,EAAuB1B,EAAM,CAC5C2B,
|
|
1
|
+
{"version":3,"file":"render-to-stream.js","sources":["../../src/node/render-to-stream.ts"],"sourcesContent":[null],"names":["renderToStream","node","options","destination","PassThrough","stream","Readable","toWeb","strategy","highWaterMark","readableHighWaterMark","size","chunk","byteLength","rejectAll","rejectShell","resolveAll","resolveShell","allReady","Promise","resolve","reject","shellReady","catch","hasShellSettled","hasAborted","rendered","renderToPipeableStream","nonce","bootstrapScriptContent","onAllReady","onError","onShellError","error","shellError","Error","String","onShellReady","abort","reason","onAbort","signal","cleanup","removeEventListener","aborted","addEventListener","once","then","hasStarted","start","pipe"],"mappings":"kHAOA,MAAMA,EAAkC,CAACC,EAAMC,KAC7C,MAAMC,EAAc,IAAIC,EAClBC,EAASC,EAASC,MAAMJ,EAAa,CACzCK,SAAU,CACRC,cAAeN,EAAYO,sBAK3BC,KAAOC,GAAsBA,EAAMC,cAGvC,IAAIC,EACAC,EACAC,EACAC,EAKJ,MAAMC,EAAW,IAAIC,QAAc,CAACC,EAASC,KAC3CP,EAAYO,EACZL,EAAaI,IAMTE,EAAa,IAAIH,QAAc,CAACC,EAASC,KAC7CN,EAAcM,EACdJ,EAAeG,IAGZF,EAASK,MAAM,QACfD,EAAWC,MAAM,QAEtB,IAAIC,GAAkB,EAClBC,GAAa,EACjB,MAAMC,EAAWC,EAAuB1B,EAAM,CAC5C2B,MAAO1B,EAAQ0B,MACfC,uBAAwB3B,EAAQ2B,uBAChCC,WAAYd,EACZe,QAAS7B,EAAQ6B,QAKjBC,aAAeC,IACb,MAAMC,EAAaD,aAAiBE,MAAQF,EAAQ,IAAIE,MAAMC,OAAOH,IAErET,GAAkB,EAClBV,EAAUoB,GACVnB,EAAYmB,IAMdG,aAAc,KACZb,GAAkB,EAClBP,OAOEqB,EAASC,IACb,IAAId,EAAJ,CASA,GALAA,GAAa,GAKRD,EAAiB,CACpBA,GAAkB,EAClB,MACMS,EAAQM,aAAkBJ,MAAQI,EAAS,IAAIJ,MADnB,iBAAXI,EAAsBA,EAAS,kBAGtDxB,EAAYkB,GACZnB,EAAUmB,EACZ,CAEAP,EAASY,MAAMC,EAhBf,GAsBIC,EAAU,IAAYF,EAAMpC,EAAQuC,OAAOF,QAK3CG,EAAU,IAAYxC,EAAQuC,OAAOE,oBAAoB,QAASH,GAEpEtC,EAAQuC,OAAOG,QACjBJ,IAEAtC,EAAQuC,OAAOI,iBAAiB,QAASL,EAAS,CAAEM,MAAM,IAGvD5B,EAAS6B,KAAKL,EAASA,GAC5B,IAAIM,GAAa,EAEjB,MAAO,CACL9B,WACAoB,QACAhB,aAKA2B,MAAO,KACAD,IACHA,GAAa,EACbtB,EAASwB,KAAK/C,KAGlBE"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lomray/vite-ssr-boost",
|
|
3
|
-
"version": "8.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "8.3.0-beta.1",
|
|
4
|
+
"description": "SSR and streaming for existing Vite + React Router apps in Data mode, without Framework mode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./node/production": {
|
|
@@ -32,7 +32,12 @@
|
|
|
32
32
|
"vite",
|
|
33
33
|
"plugin",
|
|
34
34
|
"react",
|
|
35
|
-
"ssr"
|
|
35
|
+
"ssr",
|
|
36
|
+
"react-router",
|
|
37
|
+
"server-side-rendering",
|
|
38
|
+
"data-router",
|
|
39
|
+
"streaming",
|
|
40
|
+
"spa"
|
|
36
41
|
],
|
|
37
42
|
"publishConfig": {
|
|
38
43
|
"access": "public"
|
|
@@ -51,7 +56,7 @@
|
|
|
51
56
|
"build": "rollup -c",
|
|
52
57
|
"build:watch": "rollup -c -w",
|
|
53
58
|
"docs:dev": "vitepress dev docs",
|
|
54
|
-
"docs:build": "vitepress build docs",
|
|
59
|
+
"docs:build": "vitepress build docs && node scripts/build-llms.mjs",
|
|
55
60
|
"docs:preview": "vitepress preview docs",
|
|
56
61
|
"release": "npm run build && cd lib && npm publish",
|
|
57
62
|
"lint:check": "eslint . --max-warnings=0",
|
|
@@ -63,11 +68,13 @@
|
|
|
63
68
|
"test:edge:packed": "node scripts/test-packed-edge.mjs",
|
|
64
69
|
"test:bun": "bun scripts/test-bun.mjs",
|
|
65
70
|
"test:template": "npm run build && node scripts/test-template.mjs",
|
|
66
|
-
"test:coverage": "vitest run --coverage"
|
|
71
|
+
"test:coverage": "vitest run --coverage",
|
|
72
|
+
"test:browser": "playwright test --config playwright.config.mjs"
|
|
67
73
|
},
|
|
68
74
|
"dependencies": {
|
|
69
75
|
"chalk": "^6.0.0",
|
|
70
76
|
"commander": "^15.0.0",
|
|
77
|
+
"devalue": "^5.9.2",
|
|
71
78
|
"hoist-non-react-statics": "^3.3.2",
|
|
72
79
|
"json5": "^2.2.3"
|
|
73
80
|
},
|
|
@@ -85,6 +92,7 @@
|
|
|
85
92
|
"@lomray/eslint-config": "^7.0.0",
|
|
86
93
|
"@lomray/eslint-config-react": "^7.0.0",
|
|
87
94
|
"@lomray/prettier-config": "^3.0.0",
|
|
95
|
+
"@playwright/test": "^1.63.0",
|
|
88
96
|
"@rollup/plugin-terser": "^1.0.0",
|
|
89
97
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
90
98
|
"@testing-library/react": "^16.3.3",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StaticHandlerContext } from 'react-router';
|
|
2
2
|
import Logger from './logger.js';
|
|
3
|
-
type TDiagnosticCode = 'SSR_BOOST_LOADER_NOT_SERIALIZABLE' | 'SSR_BOOST_STATE_NOT_SERIALIZABLE' | 'SSR_BOOST_OUTLET_MISSING' | 'SSR_BOOST_HYDRATION_STATE_MISSING' | 'SSR_BOOST_DUPLICATE_OUTPUT' | 'SSR_BOOST_ONRESPONSE_INVALID_RETURN';
|
|
3
|
+
type TDiagnosticCode = 'SSR_BOOST_LOADER_NOT_SERIALIZABLE' | 'SSR_BOOST_STREAM_PROMISE_ABORTED' | 'SSR_BOOST_STATE_NOT_SERIALIZABLE' | 'SSR_BOOST_OUTLET_MISSING' | 'SSR_BOOST_HYDRATION_STATE_MISSING' | 'SSR_BOOST_DUPLICATE_OUTPUT' | 'SSR_BOOST_ONRESPONSE_INVALID_RETURN';
|
|
4
4
|
interface ISerializationIssue {
|
|
5
5
|
path: string;
|
|
6
6
|
reason: string;
|
|
@@ -18,9 +18,10 @@ declare const formatDiagnostic: (code: TDiagnosticCode, sentence: string) => str
|
|
|
18
18
|
*/
|
|
19
19
|
declare const splitHtmlShell: (html: string, file: string, outlet?: string) => [string, string];
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* Custom state uses JSON. Router state also supports promises, Date, RegExp, bigint,
|
|
22
|
+
* Map and Set through the stream codec; functions, symbols, classes and cycles warn.
|
|
22
23
|
*/
|
|
23
|
-
declare const walkSerializable: (value: unknown, report: (issue: ISerializationIssue) => void, path?: string, ancestors?: Set<object
|
|
24
|
+
declare const walkSerializable: (value: unknown, report: (issue: ISerializationIssue) => void, path?: string, ancestors?: Set<object>, streamed?: boolean) => void;
|
|
24
25
|
/**
|
|
25
26
|
* Inspect one development response while allowing every chunk to stream immediately.
|
|
26
27
|
*/
|
|
@@ -44,6 +45,10 @@ declare class Diagnostics {
|
|
|
44
45
|
* Include React Router's route id and the full loader/action key path.
|
|
45
46
|
*/
|
|
46
47
|
inspectRouterState({ loaderData, actionData }: StaticHandlerContext): void;
|
|
48
|
+
/** Report the request's pending loader/action promises at the render deadline. */
|
|
49
|
+
streamAborted(count: number): void;
|
|
50
|
+
/** Inspect streamed resolutions with the same supported value matrix as initial data. */
|
|
51
|
+
inspectStreamValue(value: unknown, id: number): void;
|
|
47
52
|
/**
|
|
48
53
|
* Check custom state before the serializer can omit or coerce it.
|
|
49
54
|
*/
|
package/services/diagnostics.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import t from"./logger.js";const e="\x3c!--ssr-outlet--\x3e",o="window.__staticRouterHydrationData",
|
|
1
|
+
import t from"./logger.js";const e="\x3c!--ssr-outlet--\x3e",o="window.__staticRouterHydrationData",r=Symbol.for("@lomray/vite-ssr-boost/diagnostics"),s=globalThis,n=t=>{const e="undefined"==typeof process?void 0:process.env;return"0"===e?.SSR_BOOST_DIAGNOSTICS||"1"===e?.SSR_BOOST_DIAGNOSTICS?"1"===e.SSR_BOOST_DIAGNOSTICS:t??"production"!==e?.NODE_ENV},i=(t,e)=>`[ssr-boost] ${t}: ${e} See https://lomray-software.github.io/vite-ssr-boost/reference/diagnostics#${t.toLowerCase()}`,a=(t,o,r=e)=>{const s=t.split(r);if(!r||2!==s.length)throw new Error(i("SSR_BOOST_OUTLET_MISSING",`Invalid HTML shell in ${JSON.stringify(o)}: expected exactly one non-empty outlet ${JSON.stringify(r)}.`));return s},S=t=>{if(null===t)return"null";if("object"!=typeof t){return{bigint:"BigInt",symbol:"Symbol"}[typeof t]??typeof t}const e=Object.getPrototypeOf(t),o=e?.constructor?.name;return"string"==typeof o&&o?o:"object"},c=(t,e,o="$",r=new Set,s=!1)=>{const n=typeof t;if(s&&(t instanceof Promise||t instanceof Date||t instanceof RegExp||"bigint"===n))return;if("function"===n||"bigint"===n||"symbol"===n)return void e({path:o,reason:`${S(t)} is not JSON-serializable`});if(null===t||"object"!==n)return;const i=t,a=Object.getPrototypeOf(i);if(!(s&&(i instanceof Map||i instanceof Set)||a===Object.prototype||null===a||Array.isArray(i)&&a===Array.prototype)){const t=S(i);return void e({path:o,reason:"Date"===t?"Date hydrates as a string":`${t} is not JSON-serializable`})}if(r.has(i))return void e({path:o,reason:"a circular reference is not JSON-serializable"});r.add(i);const f=s&&i instanceof Map?[...i].flatMap(([t,e],o)=>[[`${o}.key`,t],[`${o}.value`,e]]):s&&i instanceof Set?[...i].map((t,e)=>[String(e),t]):Object.entries(i);for(const[t,n]of f){const a=Array.isArray(i)&&/^(0|[1-9]\d*)$/.test(t)?`[${t}]`:/^[A-Za-z_$][\w$]*$/.test(t)?`.${t}`:`[${JSON.stringify(t)}]`;c(n,e,o+a,r,s)}r.delete(i)};class f{route;logger;chunks=[];constructor(e,o=new t){this.route=e,this.logger=o}warn(t,e){const o=i(t,e),n=s[r]??=new Set;n.has(o)||(n.add(o),this.logger.warn(o,{}))}inspectShell({header:t,footer:o}){("string"!=typeof t||"string"!=typeof o||t.includes(e)||o.includes(e))&&this.warn("SSR_BOOST_OUTLET_MISSING",`HTML shell for route ${JSON.stringify(this.route)} must supply both header and footer around exactly one ${e} outlet, with no outlet left in either half.`)}inspectRouterState({loaderData:t,actionData:e}){for(const[o,r]of Object.entries({loaderData:t,actionData:e}))for(const[t,e]of Object.entries(r??{}))c(e,({path:e,reason:o})=>this.warn("SSR_BOOST_LOADER_NOT_SERIALIZABLE",`Route ${JSON.stringify(t)} at ${e}: ${o}.`),`${o}[${JSON.stringify(t)}]`,new Set,!0)}streamAborted(t){this.warn("SSR_BOOST_STREAM_PROMISE_ABORTED",`Route ${JSON.stringify(this.route)} aborted with ${t} pending loader/action promise(s); the browser receives a rejection when connected.`)}inspectStreamValue(t,e){c(t,({path:t,reason:e})=>this.warn("SSR_BOOST_LOADER_NOT_SERIALIZABLE",`Route ${JSON.stringify(this.route)} at ${t}: ${e}.`),`promise[${e}]`,new Set,!0)}inspectState(t){c(t,({path:t,reason:e})=>this.warn("SSR_BOOST_STATE_NOT_SERIALIZABLE",`getState for route ${JSON.stringify(this.route)} at ${t}: ${e}.`))}inspectOnResponse(t){void 0!==t&&"string"!=typeof t&&this.warn("SSR_BOOST_ONRESPONSE_INVALID_RETURN",`onResponse for route ${JSON.stringify(this.route)} returned ${S(t)}; return a string or undefined.`)}append(t){this.chunks.push(t)}complete(){const t=this.chunks.join("");this.chunks=[];const e=new Map,r=t=>{e.set(t,(e.get(t)??0)+1)},s=t.replace(/<!--[\s\S]*?-->/g,"").replace(/(<(script|style|textarea|title)\b(?:[^"'<>]|"[^"]*"|'[^']*')*>)([\s\S]*?)<\/\2\s*>/gi,(t,e,s,n)=>{if("script"===s.toLowerCase()){/\bwindow\.__staticRouterHydrationData\s*=/.test(n)&&r(o);for(const t of n.matchAll(/\$RC\s*\(\s*(["'])(B:[^"']+)\1/g))r(`$RC("${t[2]}")`)}return e});for(const t of s.matchAll(/<([a-z][\w:-]*)\b((?:[^"'<>]|"[^"]*"|'[^']*')*)>/gi)){const e=t[1].toLowerCase();"html"!==e&&"head"!==e||r(`<${e}>`);for(const e of t[2].matchAll(/([^\s=]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g)){const t=e[2]??e[3]??e[4];"id"===e[1].toLowerCase()&&/^(S|B):/.test(t)&&r(`id="${t}"`)}}e.has(o)||this.warn("SSR_BOOST_HYDRATION_STATE_MISSING",`Completed response for route ${JSON.stringify(this.route)} has no ${o} script; preserve the hydration footer in onResponse.`);for(const[t,o]of e)o>1&&this.warn("SSR_BOOST_DUPLICATE_OUTPUT",`Completed response for route ${JSON.stringify(this.route)} repeats ${t}; onResponse must return undefined to keep a chunk and '' to withhold one.`)}}export{f as default,i as formatDiagnostic,n as isDiagnosticsEnabled,a as splitHtmlShell,c as walkSerializable};
|
|
2
2
|
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.js","sources":["../../src/services/diagnostics.ts"],"sourcesContent":[null],"names":["OUTLET","HYDRATION","warnedKey","Symbol","for","registry","globalThis","isDiagnosticsEnabled","enabled","env","process","undefined","SSR_BOOST_DIAGNOSTICS","NODE_ENV","formatDiagnostic","code","sentence","toLowerCase","splitHtmlShell","html","file","outlet","parts","split","length","Error","JSON","stringify","valueType","value","bigint","symbol","prototype","Object","getPrototypeOf","name","constructor","walkSerializable","report","path","ancestors","Set","type","reason","object","Array","isArray","has","add","key","child","
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sources":["../../src/services/diagnostics.ts"],"sourcesContent":[null],"names":["OUTLET","HYDRATION","warnedKey","Symbol","for","registry","globalThis","isDiagnosticsEnabled","enabled","env","process","undefined","SSR_BOOST_DIAGNOSTICS","NODE_ENV","formatDiagnostic","code","sentence","toLowerCase","splitHtmlShell","html","file","outlet","parts","split","length","Error","JSON","stringify","valueType","value","bigint","symbol","prototype","Object","getPrototypeOf","name","constructor","walkSerializable","report","path","ancestors","Set","streamed","type","Promise","Date","RegExp","reason","object","Map","Array","isArray","has","add","entries","flatMap","key","child","index","map","String","suffix","test","delete","Diagnostics","route","logger","chunks","Logger","this","warn","detail","message","warned","inspectShell","header","footer","includes","inspectRouterState","loaderData","actionData","kind","data","streamAborted","count","inspectStreamValue","id","inspectState","state","inspectOnResponse","append","push","complete","join","markers","marker","set","get","markup","replace","_tag","opening","content","match","matchAll","attribute","total"],"mappings":"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"}
|