diff --git a/.changeset/neat-panthers-notice.md b/.changeset/neat-panthers-notice.md
new file mode 100644
index 00000000..548c986c
--- /dev/null
+++ b/.changeset/neat-panthers-notice.md
@@ -0,0 +1,5 @@
+---
+'@inox-tools/request-state': minor
+---
+
+Fixes flash of page with unsynchronized state due to response streaming.
diff --git a/docs/src/content/docs/request-nanostores.mdx b/docs/src/content/docs/request-nanostores.mdx
index f45405c1..ddd7731b 100644
--- a/docs/src/content/docs/request-nanostores.mdx
+++ b/docs/src/content/docs/request-nanostores.mdx
@@ -117,6 +117,10 @@ $comments.set(await loadCommentsForArticle());
```
+## Caveats
+
+Enabling Request-Scoped Nanostores disables [response streaming](https://docs.astro.build/en/recipes/streaming-improve-page-performance/). This behavior caused by [request-state](/request-state) package that prevents race condition where nanostores not initialized before client components starts hydrating.
+
## License
Request Nanostores is available under the MIT license.
diff --git a/docs/src/content/docs/request-state.mdx b/docs/src/content/docs/request-state.mdx
index a2a7546e..1e23a43b 100644
--- a/docs/src/content/docs/request-state.mdx
+++ b/docs/src/content/docs/request-state.mdx
@@ -130,6 +130,10 @@ document.addEventListener('@it-astro:server-state-loaded', (event) => {
});
```
+## Caveats
+
+Enabling Request State disables [response streaming](https://docs.astro.build/en/recipes/streaming-improve-page-performance/). The entire application state must be generated before shipping closing head tag to the client. This behavior prevents data race when client components start hydrating before entire document is loaded.
+
## License
Astro Request State is available under the MIT license.
diff --git a/packages/request-state/src/runtime/middleware.ts b/packages/request-state/src/runtime/middleware.ts
index 1856eb2b..cdaf3265 100644
--- a/packages/request-state/src/runtime/middleware.ts
+++ b/packages/request-state/src/runtime/middleware.ts
@@ -13,31 +13,20 @@ export const onRequest = defineMiddleware(async (_, next) => {
if (mediaType !== 'text/html' && !mediaType.startsWith('text/html+')) return result;
- const newBody = result.body
- ?.pipeThrough(new TextDecoderStream())
- .pipeThrough(injectState(getState))
- .pipeThrough(new TextEncoderStream());
-
- return new Response(newBody, result);
+ const originalBody = await result.text();
+
+ const headCloseIndex = originalBody.indexOf('');
+ if (headCloseIndex > -1) {
+ const state = getState();
+ if (state) {
+ const stateScript = ``;
+
+ return new Response(
+ originalBody.slice(0, headCloseIndex) + stateScript + originalBody.slice(headCloseIndex),
+ result
+ );
+ }
+ }
+
+ return new Response(originalBody, result);
});
-
-function injectState(getState: () => string | false) {
- let injected = false;
- return new TransformStream({
- transform(chunk, controller) {
- if (!injected) {
- const bodyCloseIndex = chunk.indexOf('