@rebask/core 0.3.0 → 0.4.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 (139) hide show
  1. package/dist/components/image.d.ts +16 -3
  2. package/dist/components/image.d.ts.map +1 -1
  3. package/dist/components/image.js +50 -68
  4. package/dist/components/link.d.ts.map +1 -1
  5. package/dist/components/link.js +6 -2
  6. package/dist/lib/image-optimization/fetch-remote-image.d.ts +17 -0
  7. package/dist/lib/image-optimization/fetch-remote-image.d.ts.map +1 -0
  8. package/dist/lib/image-optimization/fetch-remote-image.js +157 -0
  9. package/dist/lib/image-optimization/get-img-props.d.ts +3 -5
  10. package/dist/lib/image-optimization/get-img-props.d.ts.map +1 -1
  11. package/dist/lib/image-optimization/get-img-props.js +66 -40
  12. package/dist/lib/image-optimization/handler.d.ts +0 -3
  13. package/dist/lib/image-optimization/handler.d.ts.map +1 -1
  14. package/dist/lib/image-optimization/handler.js +339 -124
  15. package/dist/lib/image-optimization/image-config.d.ts +31 -4
  16. package/dist/lib/image-optimization/image-config.d.ts.map +1 -1
  17. package/dist/lib/image-optimization/image-config.js +6 -0
  18. package/dist/lib/image-optimization/image-error.d.ts +8 -0
  19. package/dist/lib/image-optimization/image-error.d.ts.map +1 -0
  20. package/dist/lib/image-optimization/image-error.js +10 -0
  21. package/dist/lib/image-optimization/image-plugin.d.ts.map +1 -1
  22. package/dist/lib/image-optimization/image-plugin.js +27 -14
  23. package/dist/lib/image-optimization/is-private-ip.d.ts +2 -0
  24. package/dist/lib/image-optimization/is-private-ip.d.ts.map +1 -0
  25. package/dist/lib/image-optimization/is-private-ip.js +43 -0
  26. package/dist/lib/image-optimization/match-patterns.d.ts +4 -0
  27. package/dist/lib/image-optimization/match-patterns.d.ts.map +1 -0
  28. package/dist/lib/image-optimization/match-patterns.js +39 -0
  29. package/dist/lib/image-optimization/read-body.d.ts +2 -0
  30. package/dist/lib/image-optimization/read-body.d.ts.map +1 -0
  31. package/dist/lib/image-optimization/read-body.js +27 -0
  32. package/dist/lib/image-optimization/static-image-loader.d.ts +2 -0
  33. package/dist/lib/image-optimization/static-image-loader.d.ts.map +1 -0
  34. package/dist/lib/image-optimization/static-image-loader.js +60 -0
  35. package/dist/lib/server-router/build-entries.d.ts.map +1 -1
  36. package/dist/lib/server-router/route-entries.js +1 -1
  37. package/dist/vite.d.ts.map +1 -1
  38. package/dist/vite.js +12 -4
  39. package/package.json +2 -1
  40. package/dist/__type_probe__.d.ts +0 -2
  41. package/dist/__type_probe__.d.ts.map +0 -1
  42. package/dist/__type_probe__.js +0 -4
  43. package/dist/components/error-boundary-client.d.ts +0 -49
  44. package/dist/components/error-boundary-client.d.ts.map +0 -1
  45. package/dist/components/error-boundary-client.js +0 -71
  46. package/dist/components/error-boundary.browser.d.ts +0 -8
  47. package/dist/components/error-boundary.browser.d.ts.map +0 -1
  48. package/dist/components/error-boundary.browser.js +0 -6
  49. package/dist/components/error.d.ts +0 -2
  50. package/dist/components/error.d.ts.map +0 -1
  51. package/dist/components/error.js +0 -5
  52. package/dist/components/not-found-activator.d.ts +0 -11
  53. package/dist/components/not-found-activator.d.ts.map +0 -1
  54. package/dist/components/not-found-activator.js +0 -26
  55. package/dist/components/not-found-boundary-client.d.ts +0 -3
  56. package/dist/components/not-found-boundary-client.d.ts.map +0 -1
  57. package/dist/components/not-found-boundary-client.js +0 -20
  58. package/dist/components/not-found-boundary.browser.d.ts +0 -8
  59. package/dist/components/not-found-boundary.browser.d.ts.map +0 -1
  60. package/dist/components/not-found-boundary.browser.js +0 -4
  61. package/dist/components/not-found-boundary.d.ts +0 -8
  62. package/dist/components/not-found-boundary.d.ts.map +0 -1
  63. package/dist/components/not-found-boundary.js +0 -9
  64. package/dist/components/not-found-thrower.d.ts +0 -2
  65. package/dist/components/not-found-thrower.d.ts.map +0 -1
  66. package/dist/components/not-found-thrower.js +0 -7
  67. package/dist/components/not-found.d.ts +0 -2
  68. package/dist/components/not-found.d.ts.map +0 -1
  69. package/dist/components/not-found.js +0 -5
  70. package/dist/components/status-page.d.ts +0 -6
  71. package/dist/components/status-page.d.ts.map +0 -1
  72. package/dist/components/status-page.js +0 -61
  73. package/dist/handler.d.ts +0 -12
  74. package/dist/handler.d.ts.map +0 -1
  75. package/dist/handler.js +0 -21
  76. package/dist/handlers/rsc/constants.d.ts +0 -3
  77. package/dist/handlers/rsc/constants.d.ts.map +0 -1
  78. package/dist/handlers/rsc/constants.js +0 -2
  79. package/dist/handlers/rsc/create-response.d.ts +0 -3
  80. package/dist/handlers/rsc/create-response.d.ts.map +0 -1
  81. package/dist/handlers/rsc/create-response.js +0 -378
  82. package/dist/handlers/rsc/render-with-retries.d.ts +0 -4
  83. package/dist/handlers/rsc/render-with-retries.d.ts.map +0 -1
  84. package/dist/handlers/rsc/render-with-retries.js +0 -154
  85. package/dist/handlers/rsc/retry-loop.d.ts +0 -3
  86. package/dist/handlers/rsc/retry-loop.d.ts.map +0 -1
  87. package/dist/handlers/rsc/retry-loop.js +0 -145
  88. package/dist/handlers/rsc/stream-rsc-payload.d.ts +0 -9
  89. package/dist/handlers/rsc/stream-rsc-payload.d.ts.map +0 -1
  90. package/dist/handlers/rsc/stream-rsc-payload.js +0 -20
  91. package/dist/handlers/rsc/types.d.ts +0 -26
  92. package/dist/handlers/rsc/types.d.ts.map +0 -1
  93. package/dist/handlers/rsc/types.js +0 -7
  94. package/dist/handlers/rsc.d.ts +0 -20
  95. package/dist/handlers/rsc.d.ts.map +0 -1
  96. package/dist/handlers/rsc.js +0 -872
  97. package/dist/integration.d.ts +0 -14
  98. package/dist/integration.d.ts.map +0 -1
  99. package/dist/integration.js +0 -9
  100. package/dist/lib/dev-module-load-race.d.ts +0 -8
  101. package/dist/lib/dev-module-load-race.d.ts.map +0 -1
  102. package/dist/lib/dev-module-load-race.js +0 -31
  103. package/dist/lib/dev-page-exports.d.ts +0 -5
  104. package/dist/lib/dev-page-exports.d.ts.map +0 -1
  105. package/dist/lib/dev-page-exports.js +0 -14
  106. package/dist/lib/environment-names.d.ts +0 -11
  107. package/dist/lib/environment-names.d.ts.map +0 -1
  108. package/dist/lib/environment-names.js +0 -10
  109. package/dist/lib/initial-hash-scroll.d.ts.map +0 -1
  110. package/dist/lib/not-found.d.ts +0 -5
  111. package/dist/lib/not-found.d.ts.map +0 -1
  112. package/dist/lib/not-found.js +0 -7
  113. package/dist/lib/page-exports.d.ts +0 -9
  114. package/dist/lib/page-exports.d.ts.map +0 -1
  115. package/dist/lib/page-exports.js +0 -47
  116. package/dist/lib/pattern-segments.d.ts +0 -8
  117. package/dist/lib/pattern-segments.d.ts.map +0 -1
  118. package/dist/lib/pattern-segments.js +0 -22
  119. package/dist/lib/ppr/cache-status.d.ts +0 -3
  120. package/dist/lib/ppr/cache-status.d.ts.map +0 -1
  121. package/dist/lib/ppr/cache-status.js +0 -5
  122. package/dist/lib/server-router-contract.d.ts +0 -42
  123. package/dist/lib/server-router-contract.d.ts.map +0 -1
  124. package/dist/lib/server-router-contract.js +0 -6
  125. package/dist/lib/server-router-loader.d.ts +0 -10
  126. package/dist/lib/server-router-loader.d.ts.map +0 -1
  127. package/dist/lib/server-router-loader.js +0 -180
  128. package/dist/lib/server-router.d.ts +0 -8
  129. package/dist/lib/server-router.d.ts.map +0 -1
  130. package/dist/lib/server-router.js +0 -173
  131. package/dist/plugins/ppr-upgrade.d.ts +0 -36
  132. package/dist/plugins/ppr-upgrade.d.ts.map +0 -1
  133. package/dist/plugins/ppr-upgrade.js +0 -32
  134. package/dist/plugins/server-router-fallback.d.ts +0 -15
  135. package/dist/plugins/server-router-fallback.d.ts.map +0 -1
  136. package/dist/plugins/server-router-fallback.js +0 -30
  137. package/dist/server.d.ts +0 -10
  138. package/dist/server.d.ts.map +0 -1
  139. package/dist/server.js +0 -57
@@ -1 +0,0 @@
1
- {"version":3,"file":"not-found-boundary.d.ts","sourceRoot":"","sources":["../../src/components/not-found-boundary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,UAAU,qBAAqB;IAC9B,QAAQ,EAAE,SAAS,CAAA;IACnB,QAAQ,EAAE,SAAS,CAAA;CACnB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,qBAAqB,+BAa7E"}
@@ -1,9 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getActiveNotFoundBoundary } from "../lib/render-context.js";
3
- import { registerNotFoundBoundary } from "../request-context.js";
4
- import { NotFoundBoundaryClient } from "./not-found-boundary-client.js";
5
- export function NotFoundBoundary({ children, fallback }) {
6
- const boundaryIndex = registerNotFoundBoundary(fallback);
7
- const isErrorActive = getActiveNotFoundBoundary() === boundaryIndex;
8
- return (_jsx(NotFoundBoundaryClient, { boundaryKey: `not-found:${boundaryIndex}`, fallback: fallback, hasError: isErrorActive, children: children }));
9
- }
@@ -1,2 +0,0 @@
1
- export default function NotFoundThrower(): null;
2
- //# sourceMappingURL=not-found-thrower.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"not-found-thrower.d.ts","sourceRoot":"","sources":["../../src/components/not-found-thrower.tsx"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,eAAe,SAGtC"}
@@ -1,7 +0,0 @@
1
- import { notFound } from "../lib/not-found.js";
2
- import { getActiveNotFoundBoundary } from "../lib/render-context.js";
3
- export default function NotFoundThrower() {
4
- if (getActiveNotFoundBoundary() === undefined)
5
- notFound();
6
- return null;
7
- }
@@ -1,2 +0,0 @@
1
- export default function DefaultNotFound(): import("react").JSX.Element;
2
- //# sourceMappingURL=not-found.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"not-found.d.ts","sourceRoot":"","sources":["../../src/components/not-found.tsx"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,eAAe,gCAOtC"}
@@ -1,5 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { StatusPage } from "./status-page.js";
3
- export default function DefaultNotFound() {
4
- return (_jsx(StatusPage, { title: "404 - Page Not Found", description: "The page you are looking for could not be found." }));
5
- }
@@ -1,6 +0,0 @@
1
- /** Document rendered by the built-in 404 and 500 pages. */
2
- export declare function StatusPage({ title, description }: {
3
- title: string;
4
- description: string;
5
- }): import("react").JSX.Element;
6
- //# sourceMappingURL=status-page.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"status-page.d.ts","sourceRoot":"","sources":["../../src/components/status-page.tsx"],"names":[],"mappings":"AAyDA,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,+BAiBxF"}
@@ -1,61 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- const styles = `
3
- :root {
4
- color-scheme: light dark;
5
- }
6
- body {
7
- margin: 0;
8
- min-height: 100vh;
9
- display: flex;
10
- align-items: center;
11
- justify-content: center;
12
- padding: 2rem;
13
- box-sizing: border-box;
14
- background: #fafafa;
15
- color: #0a0a0a;
16
- font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
17
- "Helvetica Neue", Arial, sans-serif;
18
- font-feature-settings: "cv11", "ss01";
19
- -webkit-font-smoothing: antialiased;
20
- }
21
- .rebask-status {
22
- max-width: 32rem;
23
- padding: 2.5rem 3rem;
24
- border: 1px solid #eaeaea;
25
- border-radius: 12px;
26
- background: #fff;
27
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.04);
28
- text-align: center;
29
- }
30
- .rebask-status h1 {
31
- margin: 0 0 0.5rem;
32
- font-size: 1.25rem;
33
- font-weight: 600;
34
- line-height: 1.3;
35
- letter-spacing: -0.02em;
36
- }
37
- .rebask-status p {
38
- margin: 0;
39
- font-size: 0.9375rem;
40
- line-height: 1.6;
41
- color: #666;
42
- }
43
- @media (prefers-color-scheme: dark) {
44
- body {
45
- background: #000;
46
- color: #ededed;
47
- }
48
- .rebask-status {
49
- border-color: #262626;
50
- background: #0a0a0a;
51
- box-shadow: none;
52
- }
53
- .rebask-status p {
54
- color: #a1a1a1;
55
- }
56
- }
57
- `;
58
- /** Document rendered by the built-in 404 and 500 pages. */
59
- export function StatusPage({ title, description }) {
60
- return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "utf-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { children: title }), _jsx("style", { children: styles })] }), _jsx("body", { children: _jsxs("div", { className: "rebask-status", children: [_jsx("h1", { children: title }), _jsx("p", { children: description })] }) })] }));
61
- }
package/dist/handler.d.ts DELETED
@@ -1,12 +0,0 @@
1
- export interface CreateRequestHandlerOptions {
2
- /** Vite build output directory. */
3
- root: string | URL;
4
- /** Your server's static file handler. It runs after proxy routes and before app routes. */
5
- serveStatic?: (request: Request) => Response | null | Promise<Response | null>;
6
- }
7
- export interface RebaskRequestHandler {
8
- fetch(request: Request): Promise<Response>;
9
- }
10
- /** Build the request order Rebask expects: proxy routes, static files, then app routes. */
11
- export declare function createRequestHandler(options: CreateRequestHandlerOptions): Promise<RebaskRequestHandler>;
12
- //# sourceMappingURL=handler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,2BAA2B;IAC3C,mCAAmC;IACnC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAA;IAClB,2FAA2F;IAC3F,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;CAC9E;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAC1C;AAOD,2FAA2F;AAC3F,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,2BAA2B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAoB/B"}
package/dist/handler.js DELETED
@@ -1,21 +0,0 @@
1
- import { join, resolve } from "node:path";
2
- import { fileURLToPath, pathToFileURL } from "node:url";
3
- /** Build the request order Rebask expects: proxy routes, static files, then app routes. */
4
- export async function createRequestHandler(options) {
5
- const root = options.root instanceof URL ? fileURLToPath(options.root) : resolve(options.root);
6
- process.env.REBASK_BUILD_DIR = join(root, ".rebask");
7
- const entry = (await import(pathToFileURL(join(root, "rsc", "index.js")).href));
8
- return {
9
- async fetch(request) {
10
- const proxyResponse = await entry.handleProxy(request);
11
- if (proxyResponse)
12
- return proxyResponse;
13
- if (options.serveStatic) {
14
- const staticResponse = await options.serveStatic(request);
15
- if (staticResponse)
16
- return staticResponse;
17
- }
18
- return entry.handleApp(request);
19
- },
20
- };
21
- }
@@ -1,3 +0,0 @@
1
- export declare const STATIC = 31536000;
2
- export declare const CRAWLER_USER_AGENT_RE: RegExp;
3
- //# sourceMappingURL=constants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/handlers/rsc/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM,WAAW,CAAA;AAE9B,eAAO,MAAM,qBAAqB,QAC+Q,CAAA"}
@@ -1,2 +0,0 @@
1
- export const STATIC = 31536000; // 365 days
2
- export const CRAWLER_USER_AGENT_RE = /Googlebot(?!-)|Googlebot$|Mediapartners-Google|AdsBot-Google|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview/i;
@@ -1,3 +0,0 @@
1
- import { type CacheLookupOutcome, type RenderRequestState } from "./types.js";
2
- export declare function renderToResponse(state: RenderRequestState, cacheContext: CacheLookupOutcome, rscStream: ReadableStream<Uint8Array>): Promise<Response>;
3
- //# sourceMappingURL=create-response.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create-response.d.ts","sourceRoot":"","sources":["../../../src/handlers/rsc/create-response.ts"],"names":[],"mappings":"AAsDA,OAAO,EAAmB,KAAK,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAoC9F,wBAAsB,gBAAgB,CACrC,KAAK,EAAE,kBAAkB,EACzB,YAAY,EAAE,kBAAkB,EAChC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GACnC,OAAO,CAAC,QAAQ,CAAC,CA+KnB"}
@@ -1,378 +0,0 @@
1
- import { injectRSCPayload } from "rsc-html-stream/server";
2
- import { proxyPatterns } from "virtual:rebask/proxy-router";
3
- import { errorModules } from "../../lib/app-manifest.js";
4
- import { scheduleBackgroundRevalidation } from "../../lib/background-revalidation.js";
5
- import {} from "../../lib/cache-context.js";
6
- import { getDeploymentId, getDeploymentScopedCacheKey, REBASK_DEPLOYMENT_ID_HEADER, } from "../../lib/deployment-id.js";
7
- import { sendDevWarning } from "../../lib/dev-server.js";
8
- import { noPrerenderNotFoundError, noPrerenderWarning } from "../../lib/messages.js";
9
- import { getCacheControlHeader, REBASK_PRERENDER_HEADER } from "../../lib/ppr/headers.js";
10
- import { serializeResumeState } from "../../lib/ppr/postponed-state.js";
11
- import { ResumeMode } from "../../lib/ppr/types.js";
12
- import { prerenderPaths } from "../../lib/prerender-paths.js";
13
- import { getActiveErrorBoundary, getNearestErrorBoundaryIndex, getNearestNotFoundBoundaryIndex, maybeAbort, RenderStorage, } from "../../lib/render-context.js";
14
- import { cacheRscStream, createRscResponse, renderRsc } from "../../lib/rsc-request.js";
15
- import { waitForMicrotaskDrain } from "../../lib/scheduler-patch.js";
16
- import { encodeShellParams } from "../../lib/shell-params.js";
17
- import { chainStreams } from "../../lib/stream-utils.js";
18
- import { ActionErrorCode } from "../../lib/types.js";
19
- import { getBoundaryError, getCacheLife, hasRenderError, hasRequestIO, isNotFound, markRenderError, mergeResponseHeaders, notFoundWasThrown, } from "../../request-context.js";
20
- import { renderFullPageInBackground, renderPartialShellInBackground, withBackgroundHtmlWrite, } from "./background-render.js";
21
- import { cacheHtml } from "./cache-html.js";
22
- import { STATIC } from "./constants.js";
23
- import { buildDefaultErrorRoute, buildErrorRoute, FallbackRouteError, onNotFound, RetryWithBoundaryError, RetryWithNotFoundBoundaryError, } from "./errors.js";
24
- import { getSSREntryModule } from "./ssr-entry.js";
25
- import { CacheLookupKind } from "./types.js";
26
- function getResponseStatus(state) {
27
- // If the action threw an error, we consider the response a 500.
28
- if (state.postBody.returnValue?.ok === false)
29
- return 500;
30
- if (state.isErrorRoute || getActiveErrorBoundary() !== undefined)
31
- return 500;
32
- if (state.isNotFoundRoute || isNotFound())
33
- return 404;
34
- if (state.isRscRequest)
35
- return 200;
36
- if (state.postBody.actionError === ActionErrorCode.NotFound)
37
- return 404;
38
- return 200;
39
- }
40
- const closingTagsBytes = new TextEncoder().encode("</body></html>");
41
- /** Stream RSC payload for ResumeMode.RSC. */
42
- function streamRSCPayload(rscStream) {
43
- const closingStream = new ReadableStream({
44
- start(controller) {
45
- controller.enqueue(closingTagsBytes);
46
- controller.close();
47
- },
48
- });
49
- // The transform reads the closing tags, waits for RSC data, and emits the RSC payload as script
50
- // tags followed by the closing tags.
51
- return closingStream.pipeThrough(injectRSCPayload(rscStream));
52
- }
53
- export async function renderToResponse(state, cacheContext, rscStream) {
54
- if (state.isRscRequest) {
55
- const rscStatus = getResponseStatus(state);
56
- const isCacheableRsc = !state.isPost && !state.isErrorRoute && !state.resumeState;
57
- const isCleanRender = !hasRequestIO() && !hasRenderError() && !isNotFound();
58
- // See if the RSC can be cached
59
- if (isCacheableRsc && isCleanRender) {
60
- const [responseStream, cacheStream] = rscStream.tee();
61
- cacheRscStream(state.url, cacheStream).catch((error) => console.error("[rebask] Failed to cache RSC:", error));
62
- return createRscResponse(responseStream, {}, rscStatus);
63
- }
64
- return createRscResponse(rscStream, {}, rscStatus);
65
- }
66
- const ssrEntryModule = await getSSREntryModule();
67
- state.ssrEntryModule = ssrEntryModule;
68
- try {
69
- let renderResult;
70
- const { resumeState } = state;
71
- if (resumeState?.type === ResumeMode.HTML) {
72
- const [rscStream1, rscStream2] = rscStream.tee();
73
- const cache = await ssrEntryModule.getRouterCache(rscStream1, state.routeTree);
74
- const resumePromise = ssrEntryModule.resumeHTML(rscStream2, cache, resumeState.postponed, {
75
- routeTree: state.routeTree,
76
- });
77
- // HTML resume from a cached PPR shell — stream the cached shell immediately,
78
- // then resume prepares in the background and streams after the shell.
79
- if (cacheContext.kind === CacheLookupKind.PprHit) {
80
- const shellStream = new Response(cacheContext.entry.html).body;
81
- const combinedStream = chainStreams(shellStream, resumePromise);
82
- const responseStream = withBackgroundHtmlWrite(state, combinedStream, state.fullPageCacheKey, cacheContext.promotionResolvedParams);
83
- renderResult = { responseStream, isPrerenderedResume: true };
84
- }
85
- else {
86
- // External resume request - just send resume content
87
- renderResult = { responseStream: await resumePromise };
88
- }
89
- }
90
- else if (state.resumeState?.type === ResumeMode.RSC) {
91
- // External PPR resume (RSC only).
92
- //
93
- // The client already has the full cached HTML document rendered, and is requesting fresh RSC
94
- // data to reconcile the dynamic parts that were deferred. Unlike other resume modes, we
95
- // bypass React's HTML renderer entirely because the shell is already on the client.
96
- //
97
- // The response is still `text/html`, so the browser needs a valid HTML document to parse.
98
- // We create one with just the closing tags and the RSC script tags before them.
99
- // The client's HTML parser extracts those scripts and React reconciles on the client.
100
- renderResult = { responseStream: streamRSCPayload(rscStream) };
101
- }
102
- else if (state.shouldPrerender && (!state.isNoShellRoute || state.isBuildPrerender)) {
103
- // We skip prerendering if we know the route has no shell, but not at build time.
104
- renderResult = await prerenderBranch(state, rscStream);
105
- }
106
- else {
107
- // Non-prerendering path: dynamic content, streaming
108
- const [rscStream1, rscStream2] = rscStream.tee();
109
- const cache = await ssrEntryModule.getRouterCache(rscStream1, state.routeTree);
110
- let responseStream;
111
- if (state.isBotRequest) {
112
- const result = await ssrEntryModule.prerenderHTML(rscStream2, cache, {
113
- renderToCompletion: true,
114
- });
115
- responseStream = result.prelude;
116
- }
117
- else {
118
- responseStream = await ssrEntryModule.renderHTML(rscStream2, cache, {
119
- formState: state.postBody.formState,
120
- routeTree: state.routeTree,
121
- });
122
- }
123
- renderResult = { responseStream, isStatic: false, isPrerenderedResume: false };
124
- }
125
- const { responseStream, isStatic, isPrerenderedResume, cacheLife } = renderResult;
126
- // Build Cache-Control header:
127
- // - Static content: use aggregated cacheLife values (safe to cache at CDN)
128
- // - Dynamic/streaming content (including prerendered resume): no caching
129
- // because the dynamic parts change per-request
130
- const cacheControl = isStatic
131
- ? getCacheControlHeader({
132
- revalidate: cacheLife?.revalidate ?? STATIC,
133
- expire: cacheLife?.expire,
134
- })
135
- : getCacheControlHeader({ revalidate: 0 });
136
- const response = new Response(responseStream, {
137
- status: getResponseStatus(state),
138
- headers: mergeResponseHeaders({
139
- "Content-Type": "text/html; charset=utf-8",
140
- vary: "accept",
141
- "Cache-Control": cacheControl,
142
- ...(state.isNotFoundRoute && { "x-robots-tag": "noindex" }),
143
- "x-rebask-cache": state.isErrorRoute ? "MISS" : isPrerenderedResume ? "HIT" : "MISS",
144
- ...(isPrerenderedResume && { [REBASK_PRERENDER_HEADER]: "1" }),
145
- ...(getDeploymentId() ? { [REBASK_DEPLOYMENT_ID_HEADER]: getDeploymentId() } : {}),
146
- }),
147
- });
148
- // Schedule background revalidations for stale or missing entries.
149
- if (!state.isBuildPrerender &&
150
- (cacheContext.kind === CacheLookupKind.PprHit || cacheContext.kind === CacheLookupKind.Miss)) {
151
- for (const { key, resolvedParams } of cacheContext.revalidations) {
152
- if (resolvedParams) {
153
- scheduleBackgroundRevalidation(key, () => renderPartialShellInBackground(state, key, resolvedParams));
154
- }
155
- else {
156
- scheduleBackgroundRevalidation(key, () => renderFullPageInBackground(state, key));
157
- }
158
- }
159
- }
160
- return response;
161
- }
162
- catch (error) {
163
- markRenderError();
164
- // We want to throw during prerendering, instead of rendering an error page.
165
- if (state.isBuildPrerender && !isNotFound()) {
166
- throw error;
167
- }
168
- // Handle 404 if called before a Suspense boundary.
169
- if (isNotFound()) {
170
- // Render the nearest `NotFoundBoundary` only if the current render has called `notFound()`
171
- if (notFoundWasThrown()) {
172
- // `isNotFound()` is the sticky 404 status (persists across retries).
173
- // `notFoundWasThrown()` is the per-render state.
174
- const nextNotFoundIndex = getNearestNotFoundBoundaryIndex();
175
- if (nextNotFoundIndex !== undefined) {
176
- throw new RetryWithNotFoundBoundaryError(nextNotFoundIndex);
177
- }
178
- }
179
- // Fall back to the built-in default 404
180
- throw new FallbackRouteError({
181
- type: "not-found",
182
- segments: [],
183
- layouts: [],
184
- errorPath: state.route.errorPath,
185
- });
186
- }
187
- const nextBoundaryIndex = getNearestErrorBoundaryIndex();
188
- if (!state.isErrorRoute && nextBoundaryIndex !== undefined) {
189
- throw new RetryWithBoundaryError(nextBoundaryIndex, error);
190
- }
191
- const rootErrorPath = state.route.errorPath;
192
- // Once a framework error route itself fails, fall back to the built-in default.
193
- if (state.isErrorRoute) {
194
- throw new FallbackRouteError(buildDefaultErrorRoute());
195
- }
196
- if (rootErrorPath && errorModules[rootErrorPath]) {
197
- throw new FallbackRouteError(buildErrorRoute(rootErrorPath));
198
- }
199
- throw new FallbackRouteError(buildDefaultErrorRoute());
200
- }
201
- finally {
202
- state.resolveShellInFlight?.();
203
- }
204
- }
205
- async function prerenderBranch(state, rscStream) {
206
- const { temporaryReferences } = state.postBody;
207
- const ssrEntryModule = state.ssrEntryModule;
208
- // PPR: Prerender to capture static shell, then resume for dynamic content
209
- const pprContext = RenderStorage.getStore()?.ppr;
210
- const [rscStream1, rscStream2] = rscStream.tee();
211
- const cache = await ssrEntryModule.getRouterCache(rscStream1, state.routeTree);
212
- // Prerender to capture the static shell. Any suspended components
213
- // (due to dynamic functions, async data) are captured as postponed state.
214
- const result = ssrEntryModule.prerenderHTML(rscStream2, cache, {
215
- signal: pprContext?.controller.signal,
216
- onShell: () => {
217
- maybeAbort("prerender");
218
- },
219
- // For upgrade renders we want the cached HTML to render the resolved Suspense content
220
- // inline so a refresh shows real content immediately instead of using the fallback.
221
- renderToCompletion: state.isPrerenderUpgrade,
222
- });
223
- // Wait for React's microtask queue to drain, indicating Fizz is idle
224
- // and waiting at our hanging promise. Then abort to capture the static
225
- // shell.
226
- waitForMicrotaskDrain().then(() => {
227
- maybeAbort("rsc");
228
- });
229
- const { prelude, postponed } = await result;
230
- const [preludeForClient, preludeForCache] = prelude.tee();
231
- const postponedState = postponed
232
- ? serializeResumeState({ type: ResumeMode.HTML, postponed })
233
- : undefined;
234
- // When replaySlots === -1, it means the ROOT was postponed (dynamic access
235
- // happened at the top level without any Suspense boundary). In this case,
236
- // there's no static shell worth caching.
237
- // See: React's getPostponedState in ReactFizzServer.js
238
- const rootPostponed = postponed
239
- ? postponed.replaySlots === -1
240
- : false;
241
- if (rootPostponed) {
242
- if (state.isPageRoute) {
243
- prerenderPaths.registerNoShell(state.route.filePath);
244
- }
245
- if (import.meta.env.DEV) {
246
- const devWarningMessage = noPrerenderWarning(state.url.pathname);
247
- console.warn(devWarningMessage);
248
- sendDevWarning(devWarningMessage);
249
- }
250
- }
251
- // notFound() can be thrown inside a <Suspense> boundary, where it's captured as postponed
252
- // content, so the prerender still produced a shell. When that happens, activate the next
253
- // boundary and retry.
254
- if (notFoundWasThrown()) {
255
- const nextNotFoundIndex = getNearestNotFoundBoundaryIndex();
256
- if (nextNotFoundIndex !== undefined) {
257
- prelude.cancel().catch(console.error);
258
- throw new RetryWithNotFoundBoundaryError(nextNotFoundIndex);
259
- }
260
- }
261
- let responseStream;
262
- let isStatic = false;
263
- if (postponed) {
264
- // A valid shell exists if the root wasn't postponed
265
- if (state.isBuildPrerender) {
266
- // Build-time prerendering only needs the shell. Skip resume.
267
- responseStream = preludeForClient;
268
- }
269
- else {
270
- // PPR: There's postponed content (Suspense or async component suspended)
271
- if (!state.seedData) {
272
- throw new Error("Expected route seed data for PPR resume response.");
273
- }
274
- // Resume runs in a fresh RenderStorage context (preserving activated boundary indices)
275
- // so stale registry state from the prerender doesn't leak into the resume.
276
- const currentRenderContext = RenderStorage.getStore();
277
- const [resumeRscStream1, resumeRscStream2] = RenderStorage.run({
278
- errorBoundary: { activeIndex: currentRenderContext.errorBoundary.activeIndex },
279
- notFoundBoundary: {
280
- activeIndex: currentRenderContext.notFoundBoundary.activeIndex,
281
- },
282
- ppr: {
283
- controller: new AbortController(),
284
- abortOnDynamic: false,
285
- resolvedParams: state.resolvedParams,
286
- },
287
- }, () => renderRsc({
288
- seedData: state.seedData,
289
- routeTree: state.routeTree,
290
- ...(state.routePrediction && { routePrediction: state.routePrediction }),
291
- ...(proxyPatterns && { proxyPatterns }),
292
- }, { temporaryReferences }, onNotFound).tee());
293
- const resumeCache = await ssrEntryModule.getRouterCache(resumeRscStream1, state.routeTree);
294
- const resumeStream = await ssrEntryModule.resumeHTML(resumeRscStream2, resumeCache, postponed, { routeTree: state.routeTree });
295
- if (rootPostponed) {
296
- // Root was postponed - prelude is nothing (just closing tags).
297
- // Use resume stream directly which contains complete HTML.
298
- // Cancel the broken prelude to avoid resource leaks.
299
- preludeForClient.cancel().catch(console.error);
300
- preludeForCache.cancel().catch(console.error);
301
- responseStream = resumeStream;
302
- }
303
- else {
304
- // Concatenate: static shell + dynamic content
305
- const combinedStream = chainStreams(preludeForClient, resumeStream);
306
- if (state.fullPageCacheKey && state.resolvedParams.size === 0 && state.isPageRoute) {
307
- responseStream = withBackgroundHtmlWrite(state, combinedStream, state.fullPageCacheKey, state.fullParamsSet);
308
- }
309
- else {
310
- responseStream = combinedStream;
311
- }
312
- }
313
- }
314
- }
315
- else {
316
- // Fully static - no dynamic content
317
- isStatic = true;
318
- responseStream = preludeForClient;
319
- }
320
- if (state.isBuildPrerender && rootPostponed && state.isNotFoundRoute) {
321
- // Not-found pages must be prerenderable at build time
322
- throw new Error(noPrerenderNotFoundError("(default)"));
323
- }
324
- // Capture aggregated cache life values from async context.
325
- // This is done after prerendering completes when all cacheLife() calls
326
- // have been processed. Applies to both fully static pages and postponed
327
- // shells (shared + intermediate) so that tags/revalidate/expire are
328
- // preserved on the cache entry.
329
- const cacheLife = getCacheLife();
330
- // A servable static shell does not exit when:
331
- // - `rootPostponed`: dynamic data was accessed at the root with no <Suspense> to
332
- // absorb it, so React produced no prelude.
333
- // - `isNotFound()`: the render resolved to notFound(), which is never a servable shell.
334
- // The router's catch-all route for unmatched URLs is the exception — a 404 is its
335
- // shell. This is why pages must put `notFound()` behind dynamic IO inside <Suspense>.
336
- const hasServableShell = !rootPostponed && (state.isNotFoundRoute || !isNotFound());
337
- if (state.htmlCacheKey && hasServableShell && !getBoundaryError()) {
338
- // Cache the static shell so future requests can resume from it.
339
- // For fully static pages (no postponed content), `preludeForCache` is the
340
- // complete HTML and gets cached with no postponed state.
341
- const isSharedShell = !!postponedState &&
342
- state.resolvedParams.size === 0 &&
343
- (state.isPageRoute || state.isNotFoundRoute);
344
- const isIntermediateShell = state.isPageRoute && !!postponedState && state.hasIntermediateShellParams;
345
- let cacheKey = state.htmlCacheKey;
346
- if (isIntermediateShell && state.isPageRoute) {
347
- cacheKey = getDeploymentScopedCacheKey(`html:${state.route.filePath}:${encodeShellParams(state.route, state.shellParams, state.params)}`);
348
- }
349
- else if (isSharedShell && state.isPageRoute) {
350
- cacheKey = getDeploymentScopedCacheKey(`html:${state.route.filePath}`);
351
- }
352
- const cacheWrite = new Response(preludeForCache)
353
- .text()
354
- .then((html) => cacheHtml(cacheKey, html, cacheLife, postponedState));
355
- const resolve = state.resolveShellInFlight;
356
- if (resolve) {
357
- state.resolveShellInFlight = null;
358
- cacheWrite.finally(() => resolve());
359
- }
360
- // Await the write only during the build, just so that `handlePageRoute` finishes
361
- // when the cache has been written.
362
- if (state.isBuildPrerender)
363
- await cacheWrite;
364
- }
365
- if (state.isBuildPrerender && state.handleOptions?.onBuildPrerenderMeta) {
366
- state.handleOptions.onBuildPrerenderMeta({
367
- hasShell: hasServableShell,
368
- postponedState,
369
- ...(cacheLife && {
370
- cacheLife: {
371
- revalidate: cacheLife.revalidate ?? STATIC,
372
- expire: cacheLife.expire ?? cacheLife.revalidate ?? STATIC,
373
- },
374
- }),
375
- });
376
- }
377
- return { responseStream, isStatic, isPrerenderedResume: false, cacheLife };
378
- }
@@ -1,4 +0,0 @@
1
- import { type CacheLookupOutcome } from "./cache-lookup.js";
2
- import type { RenderRequestState } from "./state.js";
3
- export declare function renderWithRetries(state: RenderRequestState, cacheContext: CacheLookupOutcome): Promise<Response>;
4
- //# sourceMappingURL=render-with-retries.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"render-with-retries.d.ts","sourceRoot":"","sources":["../../../src/handlers/rsc/render-with-retries.ts"],"names":[],"mappings":"AAeA,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAS5E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AASpD,wBAAsB,iBAAiB,CACtC,KAAK,EAAE,kBAAkB,EACzB,YAAY,EAAE,kBAAkB,GAC9B,OAAO,CAAC,QAAQ,CAAC,CAkKnB"}