@rsc-kit/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/README.md +95 -0
  2. package/SECURITY.md +60 -0
  3. package/dist/action.d.ts +90 -0
  4. package/dist/action.d.ts.map +1 -0
  5. package/dist/action.js +137 -0
  6. package/dist/action.js.map +1 -0
  7. package/dist/build-rsc-vite.d.ts +39 -0
  8. package/dist/build-rsc-vite.d.ts.map +1 -0
  9. package/dist/build-rsc-vite.js +172 -0
  10. package/dist/build-rsc-vite.js.map +1 -0
  11. package/dist/cache.d.ts +25 -0
  12. package/dist/cache.d.ts.map +1 -0
  13. package/dist/cache.js +108 -0
  14. package/dist/cache.js.map +1 -0
  15. package/dist/cli.d.ts +2 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +85 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/compile.d.ts +55 -0
  20. package/dist/compile.d.ts.map +1 -0
  21. package/dist/compile.js +141 -0
  22. package/dist/compile.js.map +1 -0
  23. package/dist/devServer.d.ts +18 -0
  24. package/dist/devServer.d.ts.map +1 -0
  25. package/dist/devServer.js +70 -0
  26. package/dist/devServer.js.map +1 -0
  27. package/dist/devUrls.d.ts +11 -0
  28. package/dist/devUrls.d.ts.map +1 -0
  29. package/dist/devUrls.js +68 -0
  30. package/dist/devUrls.js.map +1 -0
  31. package/dist/embed.d.ts +21 -0
  32. package/dist/embed.d.ts.map +1 -0
  33. package/dist/embed.js +119 -0
  34. package/dist/embed.js.map +1 -0
  35. package/dist/errors.d.ts +24 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +38 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/export.d.ts +41 -0
  40. package/dist/export.d.ts.map +1 -0
  41. package/dist/export.js +100 -0
  42. package/dist/export.js.map +1 -0
  43. package/dist/files.d.ts +39 -0
  44. package/dist/files.d.ts.map +1 -0
  45. package/dist/files.js +146 -0
  46. package/dist/files.js.map +1 -0
  47. package/dist/headers.d.ts +81 -0
  48. package/dist/headers.d.ts.map +1 -0
  49. package/dist/headers.js +96 -0
  50. package/dist/headers.js.map +1 -0
  51. package/dist/host.d.ts +86 -0
  52. package/dist/host.d.ts.map +1 -0
  53. package/dist/host.js +590 -0
  54. package/dist/host.js.map +1 -0
  55. package/dist/js/ActivityRouter.d.ts +47 -0
  56. package/dist/js/ActivityRouter.d.ts.map +1 -0
  57. package/dist/js/ActivityRouter.js +87 -0
  58. package/dist/js/ActivityRouter.js.map +1 -0
  59. package/dist/js/DocumentTitle.d.ts +22 -0
  60. package/dist/js/DocumentTitle.d.ts.map +1 -0
  61. package/dist/js/DocumentTitle.js +28 -0
  62. package/dist/js/DocumentTitle.js.map +1 -0
  63. package/dist/js/Form.d.ts +54 -0
  64. package/dist/js/Form.d.ts.map +1 -0
  65. package/dist/js/Form.js +225 -0
  66. package/dist/js/Form.js.map +1 -0
  67. package/dist/js/Link.d.ts +29 -0
  68. package/dist/js/Link.d.ts.map +1 -0
  69. package/dist/js/Link.js +112 -0
  70. package/dist/js/Link.js.map +1 -0
  71. package/dist/js/PathnameProvider.d.ts +8 -0
  72. package/dist/js/PathnameProvider.d.ts.map +1 -0
  73. package/dist/js/PathnameProvider.js +24 -0
  74. package/dist/js/PathnameProvider.js.map +1 -0
  75. package/dist/js/RedirectBoundary.d.ts +18 -0
  76. package/dist/js/RedirectBoundary.d.ts.map +1 -0
  77. package/dist/js/RedirectBoundary.js +34 -0
  78. package/dist/js/RedirectBoundary.js.map +1 -0
  79. package/dist/js/SegmentBoundary.d.ts +8 -0
  80. package/dist/js/SegmentBoundary.d.ts.map +1 -0
  81. package/dist/js/SegmentBoundary.js +38 -0
  82. package/dist/js/SegmentBoundary.js.map +1 -0
  83. package/dist/js/SlotBoundary.d.ts +15 -0
  84. package/dist/js/SlotBoundary.d.ts.map +1 -0
  85. package/dist/js/SlotBoundary.js +17 -0
  86. package/dist/js/SlotBoundary.js.map +1 -0
  87. package/dist/js/createViteRscApp.d.ts +8 -0
  88. package/dist/js/createViteRscApp.d.ts.map +1 -0
  89. package/dist/js/createViteRscApp.js +185 -0
  90. package/dist/js/createViteRscApp.js.map +1 -0
  91. package/dist/js/errors.d.ts +51 -0
  92. package/dist/js/errors.d.ts.map +1 -0
  93. package/dist/js/errors.js +93 -0
  94. package/dist/js/errors.js.map +1 -0
  95. package/dist/js/navigate.d.ts +118 -0
  96. package/dist/js/navigate.d.ts.map +1 -0
  97. package/dist/js/navigate.js +780 -0
  98. package/dist/js/navigate.js.map +1 -0
  99. package/dist/js/onlineStore.d.ts +23 -0
  100. package/dist/js/onlineStore.d.ts.map +1 -0
  101. package/dist/js/onlineStore.js +42 -0
  102. package/dist/js/onlineStore.js.map +1 -0
  103. package/dist/js/pagePayload.d.ts +15 -0
  104. package/dist/js/pagePayload.d.ts.map +1 -0
  105. package/dist/js/pagePayload.js +39 -0
  106. package/dist/js/pagePayload.js.map +1 -0
  107. package/dist/js/router.d.ts +29 -0
  108. package/dist/js/router.d.ts.map +1 -0
  109. package/dist/js/router.js +40 -0
  110. package/dist/js/router.js.map +1 -0
  111. package/dist/js/section.d.ts +16 -0
  112. package/dist/js/section.d.ts.map +1 -0
  113. package/dist/js/section.js +55 -0
  114. package/dist/js/section.js.map +1 -0
  115. package/dist/js/segmentStore.d.ts +69 -0
  116. package/dist/js/segmentStore.d.ts.map +1 -0
  117. package/dist/js/segmentStore.js +127 -0
  118. package/dist/js/segmentStore.js.map +1 -0
  119. package/dist/js/slotStore.d.ts +35 -0
  120. package/dist/js/slotStore.d.ts.map +1 -0
  121. package/dist/js/slotStore.js +46 -0
  122. package/dist/js/slotStore.js.map +1 -0
  123. package/dist/js/standardSchema.d.ts +47 -0
  124. package/dist/js/standardSchema.d.ts.map +1 -0
  125. package/dist/js/standardSchema.js +41 -0
  126. package/dist/js/standardSchema.js.map +1 -0
  127. package/dist/js/useForm.d.ts +43 -0
  128. package/dist/js/useForm.d.ts.map +1 -0
  129. package/dist/js/useForm.js +164 -0
  130. package/dist/js/useForm.js.map +1 -0
  131. package/dist/js/useLinkStatus.d.ts +2 -0
  132. package/dist/js/useLinkStatus.d.ts.map +1 -0
  133. package/dist/js/useLinkStatus.js +3 -0
  134. package/dist/js/useLinkStatus.js.map +1 -0
  135. package/dist/js/useOnline.d.ts +8 -0
  136. package/dist/js/useOnline.d.ts.map +1 -0
  137. package/dist/js/useOnline.js +20 -0
  138. package/dist/js/useOnline.js.map +1 -0
  139. package/dist/js/usePathname.d.ts +9 -0
  140. package/dist/js/usePathname.d.ts.map +1 -0
  141. package/dist/js/usePathname.js +32 -0
  142. package/dist/js/usePathname.js.map +1 -0
  143. package/dist/js/useSearchParams.d.ts +2 -0
  144. package/dist/js/useSearchParams.d.ts.map +1 -0
  145. package/dist/js/useSearchParams.js +60 -0
  146. package/dist/js/useSearchParams.js.map +1 -0
  147. package/dist/manifest.d.ts +66 -0
  148. package/dist/manifest.d.ts.map +1 -0
  149. package/dist/manifest.js +13 -0
  150. package/dist/manifest.js.map +1 -0
  151. package/dist/prerender.d.ts +138 -0
  152. package/dist/prerender.d.ts.map +1 -0
  153. package/dist/prerender.js +387 -0
  154. package/dist/prerender.js.map +1 -0
  155. package/dist/redirect.d.ts +34 -0
  156. package/dist/redirect.d.ts.map +1 -0
  157. package/dist/redirect.js +108 -0
  158. package/dist/redirect.js.map +1 -0
  159. package/dist/redirectDigest.d.ts +20 -0
  160. package/dist/redirectDigest.d.ts.map +1 -0
  161. package/dist/redirectDigest.js +66 -0
  162. package/dist/redirectDigest.js.map +1 -0
  163. package/dist/request.d.ts +93 -0
  164. package/dist/request.d.ts.map +1 -0
  165. package/dist/request.js +308 -0
  166. package/dist/request.js.map +1 -0
  167. package/dist/revalidate.d.ts +43 -0
  168. package/dist/revalidate.d.ts.map +1 -0
  169. package/dist/revalidate.js +99 -0
  170. package/dist/revalidate.js.map +1 -0
  171. package/dist/routes.d.ts +37 -0
  172. package/dist/routes.d.ts.map +1 -0
  173. package/dist/routes.js +28 -0
  174. package/dist/routes.js.map +1 -0
  175. package/dist/routing.d.ts +52 -0
  176. package/dist/routing.d.ts.map +1 -0
  177. package/dist/routing.js +146 -0
  178. package/dist/routing.js.map +1 -0
  179. package/dist/runtime.d.ts +36 -0
  180. package/dist/runtime.d.ts.map +1 -0
  181. package/dist/runtime.js +86 -0
  182. package/dist/runtime.js.map +1 -0
  183. package/dist/safeUrl.d.ts +10 -0
  184. package/dist/safeUrl.d.ts.map +1 -0
  185. package/dist/safeUrl.js +40 -0
  186. package/dist/safeUrl.js.map +1 -0
  187. package/dist/streaming.d.ts +62 -0
  188. package/dist/streaming.d.ts.map +1 -0
  189. package/dist/streaming.js +108 -0
  190. package/dist/streaming.js.map +1 -0
  191. package/dist/types.d.ts +82 -0
  192. package/dist/vite.d.ts +109 -0
  193. package/dist/vite.d.ts.map +1 -0
  194. package/dist/vite.js +1909 -0
  195. package/dist/vite.js.map +1 -0
  196. package/dist/worker.d.ts +2 -0
  197. package/dist/worker.d.ts.map +1 -0
  198. package/dist/worker.js +863 -0
  199. package/dist/worker.js.map +1 -0
  200. package/package.json +223 -0
@@ -0,0 +1,108 @@
1
+ // Redirecting from inside a render.
2
+ //
3
+ // import { redirect } from '@rsc-kit/core/redirect'
4
+ //
5
+ // export default async function ProductPage({ slug }) {
6
+ // const product = await findProduct(slug)
7
+ // if (!product) redirect('/products')
8
+ // ...
9
+ // }
10
+ //
11
+ // The hard part is not throwing — it is that a redirect decided during a
12
+ // render may be decided after the response has already begun. Headers flush
13
+ // early on purpose (see the stream-start invariant), so by the time a
14
+ // component deep in a Suspense boundary changes its mind, the 200 is gone.
15
+ //
16
+ // So there are two windows, and which one a redirect lands in is decided by
17
+ // where it was thrown rather than by anything the caller does:
18
+ //
19
+ // Before the shell resolves — nothing has been written. The host answers
20
+ // with a real 3xx, or for a navigation with X-RSC-Redirect, and the browser
21
+ // never sees the page. This is the window every guard lands in, because a
22
+ // guard runs above the boundaries.
23
+ //
24
+ // After the shell resolves — the shell is already on the wire. It holds
25
+ // layouts and Suspense fallbacks, so no data from the redirecting subtree
26
+ // has been shown. The location travels to the client instead, which
27
+ // performs it as an ordinary SPA navigation.
28
+ //
29
+ // Neither window costs a buffered byte. The first exists because the host
30
+ // already awaits the shell before writing anything; the second because React
31
+ // already carries an error digest to the client.
32
+ import { assertSafeRedirect } from './safeUrl.js';
33
+ import { resolveScope } from './revalidate.js';
34
+ import { RedirectSignal } from './redirectDigest.js';
35
+ export { RedirectSignal, isRedirectSignal, redirectDigest, parseRedirectDigest } from './redirectDigest.js';
36
+ /**
37
+ * One scope, however many copies of this module exist.
38
+ *
39
+ * The app's components are bundled into the server bundle and the host is
40
+ * not, so this module is loaded twice. Two scopes would mean the component
41
+ * records in one and the host reads the other: the redirect is simply never
42
+ * honoured, and nothing on either side reports a problem.
43
+ */
44
+ const SCOPE = Symbol.for('@rsc-kit/core.redirect-scope');
45
+ const globals = globalThis;
46
+ let ready = null;
47
+ function scope() {
48
+ return globals[SCOPE] ?? null;
49
+ }
50
+ /**
51
+ * Leave this page for another one.
52
+ *
53
+ * Never returns: it throws, which stops the component that called it. Do not
54
+ * wrap a call in `try`/`catch` without rethrowing what you do not recognise —
55
+ * swallowing this turns a redirect into a blank region.
56
+ *
57
+ * `location` is typed to the routes the build found, so a redirect to a page
58
+ * that no longer exists stops compiling. Cast with `as Href` when the
59
+ * destination is computed — remembering where someone was going and sending
60
+ * them back to it is the usual case.
61
+ *
62
+ * Where it is called decides how it is delivered, and the difference matters
63
+ * for anything that must not be seen. A call above every Suspense boundary is
64
+ * answered with a status code before a byte is written. A call inside one is
65
+ * answered after the shell — which holds no data from inside the boundary,
66
+ * but does hold whatever the layouts above it rendered.
67
+ */
68
+ export function redirect(location, status = 307) {
69
+ // Refused here, at the one place every delivery path leads back to. The
70
+ // destination reaches location.href on the client and an inline script in a
71
+ // document, and a javascript: url runs in all of them.
72
+ assertSafeRedirect(location);
73
+ // A redirect is a 3xx. Anything else produces a response carrying Location
74
+ // that no browser acts on — the page renders, the redirect silently does not
75
+ // happen, and nothing says why.
76
+ if (status < 300 || status > 399) {
77
+ throw new Error('Not a redirect status: ' + status + '. A redirect is 3xx; 307 preserves the method.');
78
+ }
79
+ const store = scope()?.getStore();
80
+ // First wins. A layout that redirects and a page that also redirects should
81
+ // land where the outer one said, not wherever finished last.
82
+ if (store && !store.redirect) {
83
+ store.redirect = { location, status };
84
+ }
85
+ throw new RedirectSignal(location, status);
86
+ }
87
+ /** The redirect asked for during the current render, if any. */
88
+ export function currentRedirect() {
89
+ return scope()?.getStore()?.redirect ?? null;
90
+ }
91
+ /**
92
+ * Run a render with somewhere for a redirect to be recorded, and report one.
93
+ *
94
+ * `taken()` is read twice by a streaming host: once when the shell resolves,
95
+ * to answer with a status code, and again when the stream ends, for a
96
+ * redirect that arrived too late for one.
97
+ */
98
+ export async function withRedirect(run) {
99
+ if (!globals[SCOPE]) {
100
+ ready ??= resolveScope().then((resolved) => {
101
+ globals[SCOPE] ??= resolved;
102
+ });
103
+ await ready;
104
+ }
105
+ const slot = { redirect: null };
106
+ return await scope().run(slot, () => run(() => slot.redirect));
107
+ }
108
+ //# sourceMappingURL=redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirect.js","sourceRoot":"","sources":["../src/redirect.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,EAAE;AACF,sDAAsD;AACtD,EAAE;AACF,0DAA0D;AAC1D,8CAA8C;AAC9C,0CAA0C;AAC1C,UAAU;AACV,MAAM;AACN,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAC5E,sEAAsE;AACtE,2EAA2E;AAC3E,EAAE;AACF,4EAA4E;AAC5E,+DAA+D;AAC/D,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAC5E,qCAAqC;AACrC,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,sEAAsE;AACtE,+CAA+C;AAC/C,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,iDAAiD;AAEjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAGpD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAa3G;;;;;;;GAOG;AACH,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;AAExD,MAAM,OAAO,GAAG,UAA8C,CAAA;AAE9D,IAAI,KAAK,GAAyB,IAAI,CAAA;AAEtC,SAAS,KAAK;IACZ,OAAQ,OAAO,CAAC,KAAK,CAAuB,IAAI,IAAI,CAAA;AACtD,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAc,EAAE,MAAM,GAAG,GAAG;IACnD,wEAAwE;IACxE,4EAA4E;IAC5E,uDAAuD;IACvD,kBAAkB,CAAC,QAAQ,CAAC,CAAA;IAE5B,2EAA2E;IAC3E,6EAA6E;IAC7E,gCAAgC;IAChC,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,yBAAyB,GAAG,MAAM,GAAG,gDAAgD,CACtF,CAAA;IACH,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAA;IAEjC,4EAA4E;IAC5E,6DAA6D;IAC7D,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7B,KAAK,CAAC,QAAQ,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;IACvC,CAAC;IAED,MAAM,IAAI,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;AAC5C,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,QAAQ,IAAI,IAAI,CAAA;AAC9C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAoD;IAEpD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,KAAK,KAAK,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YACzC,OAAO,CAAC,KAAK,CAAC,KAAK,QAA4B,CAAA;QACjD,CAAC,CAAC,CAAA;QAEF,MAAM,KAAK,CAAA;IACb,CAAC;IAED,MAAM,IAAI,GAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAA;IAErC,OAAO,MAAM,KAAK,EAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;AACjE,CAAC"}
@@ -0,0 +1,20 @@
1
+ export interface Redirection {
2
+ location: string;
3
+ /**
4
+ * 307 by default rather than 302: it preserves the method, so a redirect out
5
+ * of a POST does not silently become a GET of the target.
6
+ */
7
+ status: number;
8
+ }
9
+ /** Thrown to stop rendering the subtree that redirected. */
10
+ export declare class RedirectSignal extends Error {
11
+ readonly location: string;
12
+ readonly status: number;
13
+ constructor(location: string, status: number);
14
+ }
15
+ export declare function isRedirectSignal(error: unknown): error is RedirectSignal;
16
+ /** The digest for a redirect, or null for any other error. */
17
+ export declare function redirectDigest(error: unknown): string | null;
18
+ /** The redirect a digest describes, or null if it describes something else. */
19
+ export declare function parseRedirectDigest(digest: unknown): Redirection | null;
20
+ //# sourceMappingURL=redirectDigest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirectDigest.d.ts","sourceRoot":"","sources":["../src/redirectDigest.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;CACf;AAgBD,4DAA4D;AAC5D,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,QAAQ,EAAE,MAAM,CAAA;IAChC,SAAgB,MAAM,EAAE,MAAM,CAAA;IAE9B,YAAY,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAM3C;CACF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAMxE;AAYD,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI5D;AAED,+EAA+E;AAC/E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAcvE"}
@@ -0,0 +1,66 @@
1
+ // What a redirect is, and how it survives every boundary it has to cross.
2
+ //
3
+ // Its own module because three graphs need it and none of them can import the
4
+ // others' halves: the app bundle (where a component calls redirect()), the
5
+ // engine (which turns it into a digest), and the browser (which performs it).
6
+ // Nothing here imports anything, so all three can have it.
7
+ /**
8
+ * The mark that says an error is a redirect.
9
+ *
10
+ * A property rather than `instanceof`, for the reason this project keeps
11
+ * running into: the app's components are bundled separately from the engine
12
+ * that renders them, so each gets its own copy of this module and its own copy
13
+ * of the class. `instanceof` compares identity across that seam and is simply
14
+ * false — the redirect renders as an unhandled error, and the only clue is
15
+ * that the page went blank instead of moving.
16
+ *
17
+ * Symbol.for, so the two copies agree on the key as well as the value.
18
+ */
19
+ const MARK = Symbol.for('@rsc-kit/core.redirect-signal');
20
+ /** Thrown to stop rendering the subtree that redirected. */
21
+ export class RedirectSignal extends Error {
22
+ location;
23
+ status;
24
+ constructor(location, status) {
25
+ super(`Redirect to ${location}`);
26
+ this.name = 'RedirectSignal';
27
+ this.location = location;
28
+ this.status = status;
29
+ this[MARK] = true;
30
+ }
31
+ }
32
+ export function isRedirectSignal(error) {
33
+ return (typeof error === 'object' &&
34
+ error !== null &&
35
+ error[MARK] === true);
36
+ }
37
+ /**
38
+ * The prefix that carries a redirect inside React's error digest.
39
+ *
40
+ * React replaces a server error's message with an opaque digest in production,
41
+ * and the digest is the one part it is guaranteed to transmit. A redirect
42
+ * decided after the shell has no header left to travel in — the status line is
43
+ * already sent — so it travels here.
44
+ */
45
+ const PREFIX = 'RSC_REDIRECT;';
46
+ /** The digest for a redirect, or null for any other error. */
47
+ export function redirectDigest(error) {
48
+ if (!isRedirectSignal(error))
49
+ return null;
50
+ return `${PREFIX}${error.status};${error.location}`;
51
+ }
52
+ /** The redirect a digest describes, or null if it describes something else. */
53
+ export function parseRedirectDigest(digest) {
54
+ if (typeof digest !== 'string' || !digest.startsWith(PREFIX))
55
+ return null;
56
+ const rest = digest.slice(PREFIX.length);
57
+ const separator = rest.indexOf(';');
58
+ if (separator === -1)
59
+ return null;
60
+ const status = Number(rest.slice(0, separator));
61
+ const location = rest.slice(separator + 1);
62
+ if (!location)
63
+ return null;
64
+ return { location, status: Number.isFinite(status) ? status : 307 };
65
+ }
66
+ //# sourceMappingURL=redirectDigest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redirectDigest.js","sourceRoot":"","sources":["../src/redirectDigest.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,8EAA8E;AAC9E,2DAA2D;AAW3D;;;;;;;;;;;GAWG;AACH,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;AAExD,4DAA4D;AAC5D,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvB,QAAQ,CAAQ;IAChB,MAAM,CAAQ;IAE9B,YAAY,QAAgB,EAAE,MAAc;QAC1C,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAA;QAChC,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAA;QAC5B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CACnB;QAAC,IAA2C,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC5D,CAAC;CACF;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAAiC,CAAC,IAAI,CAAC,KAAK,IAAI,CAClD,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,GAAG,eAAe,CAAA;AAE9B,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAEzC,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAA;AACrD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,mBAAmB,CAAC,MAAe;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAA;IAEzE,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAEnC,IAAI,SAAS,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAEjC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAA;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;IAE1C,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;AACrE,CAAC"}
@@ -0,0 +1,93 @@
1
+ /** What a host can supply: a real Request, or the parts of one. */
2
+ export type RequestLike = Request | {
3
+ url: string;
4
+ headers: Record<string, string>;
5
+ } | null;
6
+ /**
7
+ * The request's headers.
8
+ *
9
+ * Empty during a build, where there is no request: the page is marked as
10
+ * needing one instead, and rendered on demand rather than frozen.
11
+ */
12
+ export declare function headers(): Promise<Headers>;
13
+ /** How a cookie should be written. The names browsers use. */
14
+ export interface CookieOptions {
15
+ path?: string;
16
+ domain?: string;
17
+ maxAge?: number;
18
+ expires?: Date;
19
+ httpOnly?: boolean;
20
+ secure?: boolean;
21
+ sameSite?: 'strict' | 'lax' | 'none';
22
+ partitioned?: boolean;
23
+ }
24
+ export interface Cookies {
25
+ get(name: string): string | undefined;
26
+ has(name: string): boolean;
27
+ getAll(): Record<string, string>;
28
+ /**
29
+ * Write one on the response.
30
+ *
31
+ * Only from a server action, which has a response of its own that has not
32
+ * been sent. A render has already flushed its headers by the time a
33
+ * component runs — that is what makes the first paint fast — so this throws
34
+ * there rather than appearing to work.
35
+ */
36
+ set(name: string, value: string, options?: CookieOptions): void;
37
+ /** Write one that expires immediately. Same rule about where. */
38
+ delete(name: string, options?: CookieOptions): void;
39
+ }
40
+ /** Kept for the name it had when it could only read. */
41
+ export type ReadonlyCookies = Cookies;
42
+ export declare function responseHeaders(): Headers;
43
+ /**
44
+ * Run a request with a response that can still be changed, and take what was
45
+ * put on it.
46
+ *
47
+ * `seal()` is called by the host the moment it builds the Response, so
48
+ * anything set afterwards is refused instead of silently going nowhere.
49
+ */
50
+ export declare function withResponseDraft<T>(run: (draft: {
51
+ taken: () => Headers;
52
+ seal: () => void;
53
+ }) => Promise<T>): Promise<T>;
54
+ /** `name=value; Path=/; HttpOnly` — the header a browser expects. */
55
+ export declare function serializeCookie(cookie: {
56
+ name: string;
57
+ value: string;
58
+ options: CookieOptions;
59
+ }): string;
60
+ export declare function cookies(): Promise<Cookies>;
61
+ /**
62
+ * The whole request, for a host-specific need the accessors do not cover.
63
+ *
64
+ * Null on a host that forwards only the parts — the worker behind Laravel has
65
+ * a socket, not a request. Use headers() and cookies(), which work everywhere.
66
+ */
67
+ export declare function request(): Promise<Request | null>;
68
+ /** The url this request was made to, whichever way the host supplied it. */
69
+ export declare function url(): Promise<string | null>;
70
+ /**
71
+ * Run one request with its headers readable.
72
+ *
73
+ * `null` is the build: a scope with nothing in it, so a page that reads is
74
+ * caught rather than silently frozen holding whatever the machine that built
75
+ * it happened to send.
76
+ */
77
+ export declare function withRequest<T>(from: RequestLike, run: () => Promise<T>): Promise<T>;
78
+ /**
79
+ * Whether anything read the request during the scope that is open.
80
+ *
81
+ * For the prerenderer, which opens one with no request and asks afterwards.
82
+ */
83
+ export declare function requestWasRead(): boolean;
84
+ /**
85
+ * The query string, as a page receives it.
86
+ *
87
+ * Derived from the request rather than passed down the render, so no host has
88
+ * to forward it separately — and so it suspends during a build for the same
89
+ * reason every other read does. A frozen page cannot know the query it will be
90
+ * asked for.
91
+ */
92
+ export declare function searchParams(): Promise<URLSearchParams>;
93
+ //# sourceMappingURL=request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AAiCA,mEAAmE;AACnE,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CAAA;AAsD3F;;;;;GAKG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAIhD;AAED,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;IACpC,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACrC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAC1B,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;;;;;;OAOG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;IAC/D,iEAAiE;IACjE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;CACpD;AAED,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,OAAO,CAAA;AAoGrC,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,GAAG,EAAE,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,IAAI,CAAA;CAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GACrE,OAAO,CAAC,CAAC,CAAC,CAmBZ;AAgBD,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GAAG,MAAM,CAkDvG;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAqBhD;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAIvD;AAED,4EAA4E;AAC5E,wBAAsB,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIlD;AA4BD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAmBzF;AAeD;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,eAAe,CAAC,CAI7D"}
@@ -0,0 +1,308 @@
1
+ // Reading the request from inside a render.
2
+ //
3
+ // import { headers, cookies } from '@rsc-kit/core/request'
4
+ //
5
+ // export default async function middleware() {
6
+ // const locale = cookies().get('locale') ?? negotiate(headers().get('accept-language'))
7
+ // if (!locale) redirect('/en')
8
+ // }
9
+ //
10
+ // Server components have no arguments beyond their props, and middleware has
11
+ // none at all, so without this an app on a JavaScript host cannot see a header
12
+ // — no locale negotiation, no subdomain, no cookie. The Laravel host escaped
13
+ // that through rpc(), because PHP has the request; this is the same thing for
14
+ // everyone else.
15
+ //
16
+ // Read-only on purpose. Setting a cookie means writing a response header, and
17
+ // by the time a component renders the shell may already have been flushed — an
18
+ // API that appears to set one and silently does not is worse than not having
19
+ // it. Set them in the host, which owns the response.
20
+ //
21
+ // Asynchronous on purpose too, and not for ergonomics. A build has no request,
22
+ // so a read there suspends and never settles — which is the same thing the
23
+ // prerender probe does to a host call. Anything still waiting when the probe's
24
+ // budget expires becomes a fallback in the frozen shell, so a read inside a
25
+ // Suspense boundary leaves the shell frozen and makes only that boundary
26
+ // dynamic. Reading synchronously could only mark the whole route dynamic,
27
+ // because there would be nothing to suspend on.
28
+ //
29
+ // Scoped to the request, on the same store cache() uses. Two requests in
30
+ // flight cannot see each other's headers.
31
+ import { resolveScope } from './revalidate.js';
32
+ const SCOPE = Symbol.for('@rsc-kit/core.request-scope');
33
+ const globals = globalThis;
34
+ let ready = null;
35
+ function scope() {
36
+ return globals[SCOPE] ?? null;
37
+ }
38
+ function slot() {
39
+ const store = scope()?.getStore();
40
+ if (!store) {
41
+ throw new Error('No request in scope. headers() and cookies() are for a render — middleware, a layout, ' +
42
+ 'a page — and there is nothing to read outside one.');
43
+ }
44
+ store.read = true;
45
+ return store;
46
+ }
47
+ /**
48
+ * The request's headers.
49
+ *
50
+ * Empty during a build, where there is no request: the page is marked as
51
+ * needing one instead, and rendered on demand rather than frozen.
52
+ */
53
+ export async function headers() {
54
+ const store = slot();
55
+ return store.request ? store.headers : never();
56
+ }
57
+ const DRAFT = Symbol.for('@rsc-kit/core.response-draft');
58
+ let draftReady = null;
59
+ function draft() {
60
+ return globals[DRAFT] ?? null;
61
+ }
62
+ /** The open draft, or an explanation of why there is not one. */
63
+ function writable(what) {
64
+ const open = draft()?.getStore();
65
+ if (!open) {
66
+ throw new Error(`${what} needs a response that has not been sent. Middleware and server actions have one; ` +
67
+ 'a script outside a request does not.');
68
+ }
69
+ if (open.sealed) {
70
+ throw new Error(`${what} was called after the response had been sent. Headers go out before the render ` +
71
+ 'starts — that is what makes the first paint fast — so set them in middleware, which ' +
72
+ 'runs before it.');
73
+ }
74
+ return open;
75
+ }
76
+ /**
77
+ * Headers to put on the answer.
78
+ *
79
+ * Mutate it as you would any Headers. `append` is the one to reach for when a
80
+ * header may legitimately appear twice; `set` replaces.
81
+ */
82
+ /**
83
+ * The draft's headers, refusing writes once the response has gone.
84
+ *
85
+ * A proxy rather than the Headers itself: returning the live object means code
86
+ * that captured it before the response was built can go on mutating a thing
87
+ * nobody will read. Nothing in this package does that — the host copies the
88
+ * headers onto the response the instant it seals — but "safe because of the
89
+ * order two other functions happen to run in" is not a property, and an app
90
+ * holding the object across an await would find writes silently doing nothing.
91
+ */
92
+ function sealable(draft) {
93
+ const guard = (method) => (...args) => {
94
+ writable('responseHeaders()');
95
+ return draft.headers[method](...args);
96
+ };
97
+ const proxy = new Proxy(draft.headers, {
98
+ get(target, property, receiver) {
99
+ if (property === 'set' || property === 'append' || property === 'delete') {
100
+ return guard(property);
101
+ }
102
+ // A maplike forEach passes the object it was called on as the third
103
+ // callback argument, and binding to the target makes that the raw
104
+ // Headers — a live, unguarded reference handed out by the very method
105
+ // meant to be read-only. Substituted for the proxy so there is no way
106
+ // through.
107
+ if (property === 'forEach') {
108
+ return (fn, thisArg) => target.forEach((value, key) => fn.call(thisArg, value, key, proxy));
109
+ }
110
+ const value = Reflect.get(target, property, receiver);
111
+ return typeof value === 'function' ? value.bind(target) : value;
112
+ },
113
+ });
114
+ return proxy;
115
+ }
116
+ export function responseHeaders() {
117
+ return sealable(writable('responseHeaders()'));
118
+ }
119
+ /**
120
+ * Run a request with a response that can still be changed, and take what was
121
+ * put on it.
122
+ *
123
+ * `seal()` is called by the host the moment it builds the Response, so
124
+ * anything set afterwards is refused instead of silently going nowhere.
125
+ */
126
+ export async function withResponseDraft(run) {
127
+ if (!globals[DRAFT]) {
128
+ draftReady ??= resolveScope().then((resolved) => {
129
+ globals[DRAFT] ??= resolved;
130
+ });
131
+ await draftReady;
132
+ }
133
+ const open = { headers: new Headers(), sealed: false };
134
+ return await draft().run(open, () => run({
135
+ taken: () => open.headers,
136
+ seal: () => {
137
+ open.sealed = true;
138
+ },
139
+ }));
140
+ }
141
+ /**
142
+ * A cookie name, as RFC 6265 defines one: a token, so no separators at all.
143
+ *
144
+ * Checked rather than escaped because there is no escaping — a name is not a
145
+ * quoted string. An app that derives one from user input (`pref_${key}`) would
146
+ * otherwise let that input close the pair and open another: a name of
147
+ * `session=attacker; Path=/; HttpOnly; x` serializes to a header whose *first*
148
+ * pair is a session cookie the caller chose, and the browser reads the first.
149
+ */
150
+ const COOKIE_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
151
+ /** No separator may appear in an attribute either, for the same reason. */
152
+ const COOKIE_ATTRIBUTE = /[;,\r\n]/;
153
+ /** `name=value; Path=/; HttpOnly` — the header a browser expects. */
154
+ export function serializeCookie(cookie) {
155
+ if (!COOKIE_NAME.test(cookie.name)) {
156
+ throw new Error(`Not a usable cookie name: ${JSON.stringify(cookie.name)}. ` +
157
+ 'A name is a token — letters, digits and !#$%&\'*+-.^_`|~ — with no spaces, ' +
158
+ 'semicolons or equals signs. Nothing escapes them, so one cannot be encoded around.');
159
+ }
160
+ if (cookie.options.sameSite !== undefined) {
161
+ const value = String(cookie.options.sameSite).toLowerCase();
162
+ if (value !== 'strict' && value !== 'lax' && value !== 'none') {
163
+ throw new Error(`Not a SameSite value: ${JSON.stringify(cookie.options.sameSite)}. ` +
164
+ 'It is written into the header as given, so anything else becomes further attributes.');
165
+ }
166
+ }
167
+ for (const [attribute, value] of [
168
+ ['path', cookie.options.path],
169
+ ['domain', cookie.options.domain],
170
+ // Trusted because it is typed as a Date — but a cast reaches this, and the
171
+ // result lands in the header verbatim like the others.
172
+ ['expires', cookie.options.expires?.toUTCString()],
173
+ ]) {
174
+ if (typeof value === 'string' && COOKIE_ATTRIBUTE.test(value)) {
175
+ throw new Error(`The cookie ${attribute} ${JSON.stringify(value)} contains a separator. ` +
176
+ 'It would be read as further attributes rather than as part of this one.');
177
+ }
178
+ }
179
+ const parts = [`${cookie.name}=${encodeURIComponent(cookie.value)}`];
180
+ const o = cookie.options;
181
+ if (o.maxAge !== undefined)
182
+ parts.push(`Max-Age=${Math.floor(o.maxAge)}`);
183
+ if (o.expires)
184
+ parts.push(`Expires=${o.expires.toUTCString()}`);
185
+ // Defaulted, because a cookie without one is scoped to the path that set it
186
+ // — a session written by POST /_rsc/action would not be sent for any page.
187
+ parts.push(`Path=${o.path ?? '/'}`);
188
+ if (o.domain)
189
+ parts.push(`Domain=${o.domain}`);
190
+ if (o.sameSite)
191
+ parts.push(`SameSite=${o.sameSite[0].toUpperCase()}${o.sameSite.slice(1)}`);
192
+ if (o.secure)
193
+ parts.push('Secure');
194
+ if (o.httpOnly)
195
+ parts.push('HttpOnly');
196
+ if (o.partitioned)
197
+ parts.push('Partitioned');
198
+ return parts.join('; ');
199
+ }
200
+ export async function cookies() {
201
+ const parsed = parseCookies((await headers()).get('cookie') ?? '');
202
+ const write = (name, value, options = {}) => {
203
+ // Appended, never set: several cookies on one response are several
204
+ // Set-Cookie headers, and replacing would leave only the last.
205
+ writable('cookies().set()').headers.append('Set-Cookie', serializeCookie({ name, value, options }));
206
+ };
207
+ return {
208
+ get: (name) => parsed[name],
209
+ has: (name) => name in parsed,
210
+ getAll: () => ({ ...parsed }),
211
+ set: write,
212
+ // Expired rather than removed: a browser drops a cookie when it is told
213
+ // one has already passed, and there is no other way to say it.
214
+ delete: (name, options = {}) => write(name, '', { ...options, maxAge: 0 }),
215
+ };
216
+ }
217
+ /**
218
+ * The whole request, for a host-specific need the accessors do not cover.
219
+ *
220
+ * Null on a host that forwards only the parts — the worker behind Laravel has
221
+ * a socket, not a request. Use headers() and cookies(), which work everywhere.
222
+ */
223
+ export async function request() {
224
+ const store = slot();
225
+ return store.request ? store.original : never();
226
+ }
227
+ /** The url this request was made to, whichever way the host supplied it. */
228
+ export async function url() {
229
+ const store = slot();
230
+ return store.request ? store.url : never();
231
+ }
232
+ function parseCookies(header) {
233
+ const out = {};
234
+ for (const part of header.split(';')) {
235
+ const eq = part.indexOf('=');
236
+ if (eq === -1)
237
+ continue;
238
+ const name = part.slice(0, eq).trim();
239
+ if (!name)
240
+ continue;
241
+ // Decoded because that is how they were written. A malformed escape is
242
+ // left as it arrived rather than throwing the render away.
243
+ const raw = part.slice(eq + 1).trim();
244
+ try {
245
+ out[name] = decodeURIComponent(raw);
246
+ }
247
+ catch {
248
+ out[name] = raw;
249
+ }
250
+ }
251
+ return out;
252
+ }
253
+ /**
254
+ * Run one request with its headers readable.
255
+ *
256
+ * `null` is the build: a scope with nothing in it, so a page that reads is
257
+ * caught rather than silently frozen holding whatever the machine that built
258
+ * it happened to send.
259
+ */
260
+ export async function withRequest(from, run) {
261
+ if (!globals[SCOPE]) {
262
+ ready ??= resolveScope().then((resolved) => {
263
+ globals[SCOPE] ??= resolved;
264
+ });
265
+ await ready;
266
+ }
267
+ const isRequest = from instanceof Request;
268
+ const store = {
269
+ request: from !== null,
270
+ url: from ? (isRequest ? from.url : from.url) : null,
271
+ headers: from ? (isRequest ? from.headers : new Headers(from.headers)) : new Headers(),
272
+ original: isRequest ? from : null,
273
+ read: false,
274
+ };
275
+ return await scope().run(store, run);
276
+ }
277
+ /**
278
+ * A promise that never settles, so the caller suspends.
279
+ *
280
+ * What a read does during a build. React treats it exactly as it treats a host
281
+ * call that never answers: the component suspends, its Suspense fallback goes
282
+ * into the shell, and the probe's budget decides the rest.
283
+ */
284
+ function never() {
285
+ slot().read = true;
286
+ return new Promise(() => { });
287
+ }
288
+ /**
289
+ * Whether anything read the request during the scope that is open.
290
+ *
291
+ * For the prerenderer, which opens one with no request and asks afterwards.
292
+ */
293
+ export function requestWasRead() {
294
+ return scope()?.getStore()?.read ?? false;
295
+ }
296
+ /**
297
+ * The query string, as a page receives it.
298
+ *
299
+ * Derived from the request rather than passed down the render, so no host has
300
+ * to forward it separately — and so it suspends during a build for the same
301
+ * reason every other read does. A frozen page cannot know the query it will be
302
+ * asked for.
303
+ */
304
+ export async function searchParams() {
305
+ const from = await url();
306
+ return from ? new URL(from).searchParams : new URLSearchParams();
307
+ }
308
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"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"}