@rsc-kit/core 0.29.1 → 0.29.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vite.js CHANGED
@@ -2932,7 +2932,7 @@ import { isSharedSection, sectionComponent } from ${JSON.stringify(join(packageD
2932
2932
  import { shareRender } from ${JSON.stringify(join(packageDir, "sharedRenders"))}
2933
2933
  import { PathnameProvider } from ${JSON.stringify(join(packageDir, "js/PathnameProvider"))}
2934
2934
  import { DefaultRouteError } from ${JSON.stringify(join(packageDir, "js/DefaultRouteError"))}
2935
- import { searchParams as requestSearchParams, withUrl } from ${JSON.stringify(join(packageDir, "request"))}
2935
+ import { requestSearch, searchParams as requestSearchParams, withUrl } from ${JSON.stringify(join(packageDir, "request"))}
2936
2936
  import { parseParams, parseSearchParams, parseBody, isSearchParamsError, isBodyError } from ${JSON.stringify(join(packageDir, "routeSchema"))}
2937
2937
  import { notFoundDigest, isNotFoundSignal } from ${JSON.stringify(join(packageDir, "notFound"))}
2938
2938
  import { noteRequestRead, notePageProps, urlOf } from ${JSON.stringify(join(packageDir, "request"))}
@@ -4378,7 +4378,7 @@ export async function handleRscHtmlStream(
4378
4378
  const [forHtml, forPayload] = flight.tee()
4379
4379
  const rscPayloadPromise = new Response(forPayload).text()
4380
4380
  const ssr = await (import.meta as any).viteRsc.loadModule('ssr', 'index')
4381
- const htmlStream = await ssr.handleSsr(forHtml, nonce, undefined, bootstrap)
4381
+ const htmlStream = await ssr.handleSsr(forHtml, nonce, undefined, bootstrap, undefined, requestSearch())
4382
4382
  return { htmlStream, rscPayloadPromise, clientChunks: {} }
4383
4383
  }
4384
4384
 
@@ -4425,7 +4425,7 @@ export async function handleRscFormPost(
4425
4425
  { onError: flightOnError },
4426
4426
  )
4427
4427
  const ssr = await (import.meta as any).viteRsc.loadModule('ssr', 'index')
4428
- const htmlStream = await ssr.handleSsr(flight, nonce, undefined, bootstrap, formState)
4428
+ const htmlStream = await ssr.handleSsr(flight, nonce, undefined, bootstrap, formState, requestSearch())
4429
4429
 
4430
4430
  return { htmlStream }
4431
4431
  }
@@ -4514,9 +4514,15 @@ export async function handleRscResume(
4514
4514
  // client-rendered. Set before the stream ends, because that is when
4515
4515
  // React reports it.
4516
4516
  let replayFailed = false
4517
- const htmlStream = await ssr.handleSsrResume(flight, postponed, nonce, () => {
4518
- replayFailed = true
4519
- })
4517
+ const htmlStream = await ssr.handleSsrResume(
4518
+ flight,
4519
+ postponed,
4520
+ nonce,
4521
+ () => {
4522
+ replayFailed = true
4523
+ },
4524
+ requestSearch(),
4525
+ )
4520
4526
 
4521
4527
  return { htmlStream, replayed: () => !replayFailed }
4522
4528
  }
@@ -4796,8 +4802,14 @@ export async function handleAction(
4796
4802
  // to ask is the whole point — the answer carries what went stale with it.
4797
4803
  const targets = takeRevalidated?.() ?? []
4798
4804
 
4805
+ // flightOnError on both, as on every other render: it is what turns a
4806
+ // redirect() or notFound() into the digest the client's boundaries read.
4807
+ // Without it a re-render that reached a redirect inside a Suspense
4808
+ // boundary - the old address of a page the action just renamed - sent an
4809
+ // anonymous error, and the boundary showed the error page instead of
4810
+ // following it.
4799
4811
  if (targets.length === 0 || !page) {
4800
- return { stream: renderToReadableStream(result) }
4812
+ return { stream: renderToReadableStream(result, { onError: flightOnError }) }
4801
4813
  }
4802
4814
 
4803
4815
  // The render is of the world after the write. Everything cache() answered
@@ -4822,7 +4834,7 @@ export async function handleAction(
4822
4834
 
4823
4835
  // Marked, so an action whose own result happens to be an object with a
4824
4836
  // 'result' key is not mistaken for this envelope.
4825
- return { stream: renderToReadableStream({ __rscRevalidated: revalidated, result }) }
4837
+ return { stream: renderToReadableStream({ __rscRevalidated: revalidated, result }, { onError: flightOnError }) }
4826
4838
  }
4827
4839
 
4828
4840
  return page.href ? await withUrl(page.href, render) : await render()
@@ -5076,13 +5088,16 @@ export async function handleRscRevalidate(
5076
5088
  await runMiddleware(page.component, page.props)
5077
5089
 
5078
5090
  const rscPayload = await shareRender(page.component + ' ' + target + ' ' + share, async () =>
5079
- new Response(renderToReadableStream(await renderRevalidated(target, page, false, true))).text(),
5091
+ new Response(renderToReadableStream(await renderRevalidated(target, page, false, true), { onError: flightOnError })).text(),
5080
5092
  )
5081
5093
 
5082
5094
  return { rscPayload }
5083
5095
  }
5084
5096
 
5085
- const flight = renderToReadableStream(await renderRevalidated(target, page))
5097
+ // A redirect the refreshed region reaches has to arrive as one - a region
5098
+ // refreshed because refreshOn heard its data change, on a page that now
5099
+ // redirects, showed the error page without the digest.
5100
+ const flight = renderToReadableStream(await renderRevalidated(target, page), { onError: flightOnError })
5086
5101
 
5087
5102
  return { rscPayload: await new Response(flight).text() }
5088
5103
  }
@@ -5521,6 +5536,8 @@ import { cancelledByConsumer, caughtByLoading } from ${JSON.stringify(fallbackRe
5521
5536
  import { parseRedirectDigest } from ${JSON.stringify(redirectDigestModule)}
5522
5537
  import { isNotFoundDigest } from ${JSON.stringify(notFoundModule)}
5523
5538
  import { EARLY_CLICKS } from ${JSON.stringify(earlyClicks)}
5539
+ import { searchSnapshotContext } from ${JSON.stringify(join(packageDir, "js/useSearchParams"))}
5540
+ import { createElement as h } from 'react'
5524
5541
  ${webManifestOptions ? `import { INSTALL_CAPTURE } from ${JSON.stringify(installCapture)}` : ""}
5525
5542
 
5526
5543
  // What runs ahead of the runtime: held taps, and - in an app that can be
@@ -5532,14 +5549,27 @@ const EARLY = EARLY_CLICKS${webManifestOptions ? " + INSTALL_CAPTURE" : ""}
5532
5549
  // modules only Vite can answer — see devUrls.ts.
5533
5550
  const DEV_ORIGIN = ${JSON.stringify(devOrigin)}
5534
5551
 
5552
+ /**
5553
+ * The tree with the query it is rendered for: the request's, so a client
5554
+ * component reading useSearchParams renders on the server like any other -
5555
+ * or null where the HTML may be stored, so it refuses and the browser
5556
+ * renders it. Always wrapped, null or not: a shell prerendered at build and
5557
+ * its holes resumed per request must be the same tree, or React cannot line
5558
+ * them up.
5559
+ */
5560
+ function withSearch(root: unknown, search: string | null | undefined): unknown {
5561
+ return h(searchSnapshotContext().Provider, { value: search ?? null }, root as any)
5562
+ }
5563
+
5535
5564
  export async function handleSsr(
5536
5565
  rscStream: ReadableStream,
5537
5566
  nonce?: string,
5538
5567
  onError?: (error: unknown) => void,
5539
5568
  bootstrap = true,
5540
5569
  formState?: unknown,
5570
+ search?: string | null,
5541
5571
  ): Promise<ReadableStream> {
5542
- const root = await createFromReadableStream(rscStream)
5572
+ const root = withSearch(await createFromReadableStream(rscStream), search)
5543
5573
 
5544
5574
  // Without the bootstrap the page ships no client runtime at all: no React,
5545
5575
  // no Flight client, no router. HTML only. A page with nothing interactive on
@@ -5585,7 +5615,8 @@ export async function handleSsrPrerender(
5585
5615
  rscStream: ReadableStream,
5586
5616
  options: { nonce?: string; bootstrap?: boolean; signal?: AbortSignal } = {},
5587
5617
  ): Promise<{ prelude: ReadableStream; postponed: unknown }> {
5588
- const root = await createFromReadableStream(rscStream)
5618
+ // Null: a prerender is stored.
5619
+ const root = withSearch(await createFromReadableStream(rscStream), null)
5589
5620
 
5590
5621
  const bootstrapScriptContent =
5591
5622
  options.bootstrap === false
@@ -5694,8 +5725,11 @@ export async function handleSsrResume(
5694
5725
  // is client-rendered instead of filled here. The caller decides what to
5695
5726
  // do about it; see the host.
5696
5727
  onReplayMismatch?: () => void,
5728
+ search?: string | null,
5697
5729
  ): Promise<ReadableStream> {
5698
- const root = await createFromReadableStream(rscStream)
5730
+ // The same tree the shell was prerendered with, now holding this
5731
+ // request's query: the holes are filled per request.
5732
+ const root = withSearch(await createFromReadableStream(rscStream), search)
5699
5733
 
5700
5734
  const html = await resume(root as any, postponed as any, {
5701
5735
  nonce,