@reckona/mreact-router 0.0.202 → 0.0.204

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 (152) hide show
  1. package/README.md +58 -11
  2. package/dist/actions.d.ts +8 -3
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +125 -45
  5. package/dist/actions.js.map +1 -1
  6. package/dist/adapters/aws-lambda.d.ts +15 -4
  7. package/dist/adapters/aws-lambda.d.ts.map +1 -1
  8. package/dist/adapters/aws-lambda.js +301 -63
  9. package/dist/adapters/aws-lambda.js.map +1 -1
  10. package/dist/adapters/cloudflare.d.ts +5 -2
  11. package/dist/adapters/cloudflare.d.ts.map +1 -1
  12. package/dist/adapters/cloudflare.js +35 -11
  13. package/dist/adapters/cloudflare.js.map +1 -1
  14. package/dist/adapters/edge.d.ts +1 -1
  15. package/dist/adapters/edge.d.ts.map +1 -1
  16. package/dist/adapters/edge.js.map +1 -1
  17. package/dist/adapters/node.d.ts +5 -3
  18. package/dist/adapters/node.d.ts.map +1 -1
  19. package/dist/adapters/node.js +2 -1
  20. package/dist/adapters/node.js.map +1 -1
  21. package/dist/adapters/static.d.ts.map +1 -1
  22. package/dist/adapters/static.js +24 -2
  23. package/dist/adapters/static.js.map +1 -1
  24. package/dist/build.d.ts +4 -1
  25. package/dist/build.d.ts.map +1 -1
  26. package/dist/build.js +185 -13
  27. package/dist/build.js.map +1 -1
  28. package/dist/built-runtime.d.ts +2 -0
  29. package/dist/built-runtime.d.ts.map +1 -1
  30. package/dist/built-runtime.js +16 -0
  31. package/dist/built-runtime.js.map +1 -1
  32. package/dist/cache.d.ts +4 -2
  33. package/dist/cache.d.ts.map +1 -1
  34. package/dist/cache.js +216 -17
  35. package/dist/cache.js.map +1 -1
  36. package/dist/cli-options.d.ts +3 -0
  37. package/dist/cli-options.d.ts.map +1 -1
  38. package/dist/cli-options.js +10 -2
  39. package/dist/cli-options.js.map +1 -1
  40. package/dist/cli.js +14 -3
  41. package/dist/cli.js.map +1 -1
  42. package/dist/client.d.ts +5 -0
  43. package/dist/client.d.ts.map +1 -1
  44. package/dist/client.js +43 -3
  45. package/dist/client.js.map +1 -1
  46. package/dist/config.d.ts +3 -0
  47. package/dist/config.d.ts.map +1 -1
  48. package/dist/config.js +21 -2
  49. package/dist/config.js.map +1 -1
  50. package/dist/csp.d.ts +1 -0
  51. package/dist/csp.d.ts.map +1 -1
  52. package/dist/csp.js +9 -0
  53. package/dist/csp.js.map +1 -1
  54. package/dist/dehydrate-policy.d.ts +3 -0
  55. package/dist/dehydrate-policy.d.ts.map +1 -0
  56. package/dist/dehydrate-policy.js +16 -0
  57. package/dist/dehydrate-policy.js.map +1 -0
  58. package/dist/dev-server.d.ts +7 -2
  59. package/dist/dev-server.d.ts.map +1 -1
  60. package/dist/dev-server.js +120 -11
  61. package/dist/dev-server.js.map +1 -1
  62. package/dist/http.d.ts +1 -1
  63. package/dist/http.d.ts.map +1 -1
  64. package/dist/http.js +147 -7
  65. package/dist/http.js.map +1 -1
  66. package/dist/index.d.ts +4 -3
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js +1 -0
  69. package/dist/index.js.map +1 -1
  70. package/dist/logger.d.ts +22 -1
  71. package/dist/logger.d.ts.map +1 -1
  72. package/dist/logger.js +22 -8
  73. package/dist/logger.js.map +1 -1
  74. package/dist/metadata.d.ts +8 -0
  75. package/dist/metadata.d.ts.map +1 -1
  76. package/dist/metadata.js +60 -22
  77. package/dist/metadata.js.map +1 -1
  78. package/dist/navigation-marker.d.ts +2 -0
  79. package/dist/navigation-marker.d.ts.map +1 -0
  80. package/dist/navigation-marker.js +357 -0
  81. package/dist/navigation-marker.js.map +1 -0
  82. package/dist/navigation-runtime.d.ts +1 -1
  83. package/dist/navigation-runtime.d.ts.map +1 -1
  84. package/dist/navigation-runtime.js +1 -1
  85. package/dist/navigation-runtime.js.map +1 -1
  86. package/dist/navigation.d.ts +1 -0
  87. package/dist/navigation.d.ts.map +1 -1
  88. package/dist/navigation.js +1 -1
  89. package/dist/navigation.js.map +1 -1
  90. package/dist/node-server.d.ts +5 -2
  91. package/dist/node-server.d.ts.map +1 -1
  92. package/dist/node-server.js +75 -6
  93. package/dist/node-server.js.map +1 -1
  94. package/dist/prerender-entry.d.ts +17 -1
  95. package/dist/prerender-entry.d.ts.map +1 -1
  96. package/dist/prerender-entry.js +98 -3
  97. package/dist/prerender-entry.js.map +1 -1
  98. package/dist/render.d.ts +16 -2
  99. package/dist/render.d.ts.map +1 -1
  100. package/dist/render.js +142 -135
  101. package/dist/render.js.map +1 -1
  102. package/dist/serve.d.ts +11 -2
  103. package/dist/serve.d.ts.map +1 -1
  104. package/dist/serve.js +67 -41
  105. package/dist/serve.js.map +1 -1
  106. package/dist/session.d.ts.map +1 -1
  107. package/dist/session.js +52 -19
  108. package/dist/session.js.map +1 -1
  109. package/dist/upgrade.d.ts +59 -2
  110. package/dist/upgrade.d.ts.map +1 -1
  111. package/dist/upgrade.js +282 -1
  112. package/dist/upgrade.js.map +1 -1
  113. package/dist/vite-config.d.ts +2 -0
  114. package/dist/vite-config.d.ts.map +1 -1
  115. package/dist/vite-config.js +2 -0
  116. package/dist/vite-config.js.map +1 -1
  117. package/dist/vite.d.ts +4 -1
  118. package/dist/vite.d.ts.map +1 -1
  119. package/dist/vite.js +117 -6
  120. package/dist/vite.js.map +1 -1
  121. package/package.json +11 -11
  122. package/src/actions.ts +146 -60
  123. package/src/adapters/aws-lambda.ts +426 -115
  124. package/src/adapters/cloudflare.ts +58 -12
  125. package/src/adapters/edge.ts +2 -0
  126. package/src/adapters/node.ts +8 -10
  127. package/src/adapters/static.ts +31 -2
  128. package/src/build.ts +217 -13
  129. package/src/built-runtime.ts +28 -0
  130. package/src/cache.ts +272 -19
  131. package/src/cli-options.ts +15 -2
  132. package/src/cli.ts +16 -2
  133. package/src/client.ts +47 -3
  134. package/src/config.ts +43 -6
  135. package/src/csp.ts +11 -0
  136. package/src/dehydrate-policy.ts +23 -0
  137. package/src/dev-server.ts +188 -15
  138. package/src/http.ts +172 -6
  139. package/src/index.ts +14 -1
  140. package/src/logger.ts +47 -10
  141. package/src/metadata.ts +125 -60
  142. package/src/navigation-marker.ts +423 -0
  143. package/src/navigation-runtime.ts +1 -0
  144. package/src/navigation.ts +1 -1
  145. package/src/node-server.ts +128 -22
  146. package/src/prerender-entry.ts +127 -5
  147. package/src/render.ts +859 -749
  148. package/src/serve.ts +112 -82
  149. package/src/session.ts +56 -25
  150. package/src/upgrade.ts +402 -3
  151. package/src/vite-config.ts +6 -0
  152. package/src/vite.ts +157 -5
@@ -1,6 +1,7 @@
1
1
  import { createServer } from "node:http";
2
2
  import { nodeRequestToWebRequest, sendResponse } from "./http.js";
3
3
  import { emitRouterLog, logDurationMs, logError, logNow, nodeRequestPath, requestLogFields, } from "./logger.js";
4
+ import { assertValidHttpUpgradeOriginPolicy, closeServerWithUpgrades, createManagedHttpUpgradeLifecycle, validateHttpUpgradeOrigin, } from "./upgrade.js";
4
5
  export function resolveNodeRequestProtocol(options) {
5
6
  if (options.encrypted) {
6
7
  return "https";
@@ -15,6 +16,10 @@ export function resolveNodeRequestProtocol(options) {
15
16
  return first === "https" ? "https" : "http";
16
17
  }
17
18
  export async function startNodeRequestServer(options) {
19
+ const upgradeCloseTimeoutMs = finiteNonNegativeTimeout(options.upgradeCloseTimeoutMs, 1_000, "upgradeCloseTimeoutMs");
20
+ const upgradeDecisionTimeoutMs = finiteNonNegativeTimeout(options.upgradeDecisionTimeoutMs, 1_000, "upgradeDecisionTimeoutMs");
21
+ assertValidHttpUpgradeOriginPolicy(options.upgradeOriginPolicy);
22
+ let listeningPort = options.port;
18
23
  const server = createServer(async (incoming, outgoing) => {
19
24
  const startedAt = logNow();
20
25
  const fallbackRequestFields = {
@@ -23,7 +28,7 @@ export async function startNodeRequestServer(options) {
23
28
  runtime: "node",
24
29
  };
25
30
  try {
26
- const fallbackHost = `${options.hostname ?? "127.0.0.1"}:${options.port}`;
31
+ const fallbackHost = formatNodeAuthority(options.hostname ?? "127.0.0.1", options.port);
27
32
  const host = (options.resolveHost ?? defaultResolveRequestHost)({
28
33
  allowedHosts: options.allowedHosts,
29
34
  fallbackHost,
@@ -35,7 +40,7 @@ export async function startNodeRequestServer(options) {
35
40
  forwardedProto: incoming.headers["x-forwarded-proto"],
36
41
  trustForwardedProto: options.trustForwardedProto,
37
42
  });
38
- const request = nodeRequestToWebRequest(incoming, `${protocol}://${host}`);
43
+ const request = nodeRequestToWebRequest(incoming, `${protocol}://${host}`, outgoing);
39
44
  const logFields = requestLogFields(request, "node");
40
45
  emitRouterLog(options.logger, "info", {
41
46
  ...logFields,
@@ -75,18 +80,82 @@ export async function startNodeRequestServer(options) {
75
80
  outgoing.end(payload.body);
76
81
  }
77
82
  });
78
- if (options.onUpgrade !== undefined) {
79
- server.on("upgrade", options.onUpgrade);
83
+ const upgradeLifecycle = options.onUpgrade === undefined
84
+ ? undefined
85
+ : createManagedHttpUpgradeLifecycle({
86
+ decisionTimeoutMs: upgradeDecisionTimeoutMs,
87
+ handler: options.onUpgrade,
88
+ isOriginAllowed: (request) => validateNodeUpgradeOrigin(request, {
89
+ ...options,
90
+ listeningPort,
91
+ }),
92
+ logger: options.logger,
93
+ });
94
+ if (upgradeLifecycle !== undefined) {
95
+ server.on("upgrade", upgradeLifecycle.handle);
80
96
  }
81
97
  await new Promise((resolve) => server.listen(options.port, options.hostname ?? "127.0.0.1", resolve));
82
98
  const address = server.address();
83
99
  const port = typeof address === "object" && address !== null ? address.port : options.port;
100
+ listeningPort = port;
101
+ let closePromise;
84
102
  return {
85
103
  server,
86
- url: `http://${options.hostname ?? "127.0.0.1"}:${port}`,
87
- close: () => new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve()))),
104
+ url: `http://${formatNodeAuthority(options.hostname ?? "127.0.0.1", port)}`,
105
+ close: () => {
106
+ closePromise ??=
107
+ upgradeLifecycle === undefined
108
+ ? new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())))
109
+ : closeServerWithUpgrades({
110
+ lifecycle: upgradeLifecycle,
111
+ server,
112
+ timeoutMs: upgradeCloseTimeoutMs,
113
+ });
114
+ return closePromise;
115
+ },
88
116
  };
89
117
  }
118
+ function validateNodeUpgradeOrigin(request, options) {
119
+ const policy = options.upgradeOriginPolicy ?? "same-origin";
120
+ if (policy === "unchecked") {
121
+ return { ok: true, origin: request.headers.origin };
122
+ }
123
+ if (typeof policy === "object") {
124
+ return validateHttpUpgradeOrigin(request, policy);
125
+ }
126
+ const fallbackHost = formatNodeAuthority(options.hostname ?? "127.0.0.1", options.listeningPort);
127
+ const host = (options.resolveHost ?? defaultResolveRequestHost)({
128
+ allowedHosts: options.allowedHosts,
129
+ fallbackHost,
130
+ hostPolicy: options.hostPolicy,
131
+ rawHost: request.headers.host,
132
+ });
133
+ const protocol = resolveNodeRequestProtocol({
134
+ encrypted: request.socket.encrypted === true,
135
+ forwardedProto: request.headers["x-forwarded-proto"],
136
+ trustForwardedProto: options.trustForwardedProto,
137
+ });
138
+ try {
139
+ return validateHttpUpgradeOrigin(request, { allowedOrigins: [`${protocol}://${host}`] });
140
+ }
141
+ catch {
142
+ return { ok: false, reason: "malformed-origin" };
143
+ }
144
+ }
145
+ function formatNodeAuthority(hostname, port) {
146
+ const host = hostname.includes(":") && !hostname.startsWith("[") ? `[${hostname}]` : hostname;
147
+ return `${host}:${port}`;
148
+ }
149
+ function finiteNonNegativeTimeout(value, fallback, name) {
150
+ const timeout = value ?? fallback;
151
+ if (!Number.isFinite(timeout) ||
152
+ timeout < 0 ||
153
+ !Number.isSafeInteger(timeout) ||
154
+ timeout > 2_147_483_647) {
155
+ throw new TypeError(`${name} must be a finite non-negative safe integer no greater than 2147483647.`);
156
+ }
157
+ return timeout;
158
+ }
90
159
  function defaultResolveRequestHost(options) {
91
160
  const raw = options.rawHost;
92
161
  if (raw === undefined || raw === "")
@@ -1 +1 @@
1
- {"version":3,"file":"node-server.js","sourceRoot":"","sources":["../src/node-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type Server } from \"node:http\";\nimport { nodeRequestToWebRequest, sendResponse } from \"./http.js\";\nimport {\n emitRouterLog,\n logDurationMs,\n logError,\n logNow,\n nodeRequestPath,\n requestLogFields,\n type AppRouterLogger,\n} from \"./logger.js\";\nimport type { HttpUpgradeHandler } from \"./upgrade.js\";\n\nexport interface StartNodeRequestServerOptions {\n allowedHosts?: readonly string[] | undefined;\n errorHandler?: ((error: unknown) => {\n body: string;\n status: number;\n headers?: Record<string, string>;\n }) | undefined;\n hostname?: string | undefined;\n hostPolicy?: \"strict\" | \"trusted-proxy\" | undefined;\n logger?: AppRouterLogger | undefined;\n onUpgrade?: HttpUpgradeHandler | undefined;\n port: number;\n render(request: Request): Promise<Response>;\n resolveHost?: ((options: {\n allowedHosts?: readonly string[] | undefined;\n fallbackHost: string;\n hostPolicy?: \"strict\" | \"trusted-proxy\" | undefined;\n rawHost: string | undefined;\n }) => string) | undefined;\n trustForwardedProto?: boolean | undefined;\n}\n\nexport function resolveNodeRequestProtocol(options: {\n encrypted: boolean;\n forwardedProto: string | readonly string[] | undefined;\n trustForwardedProto?: boolean | undefined;\n}): \"http\" | \"https\" {\n if (options.encrypted) {\n return \"https\";\n }\n\n if (options.trustForwardedProto !== true) {\n return \"http\";\n }\n\n const forwarded = Array.isArray(options.forwardedProto)\n ? options.forwardedProto[0]\n : options.forwardedProto;\n const first = forwarded?.split(\",\", 1)[0]?.trim().toLowerCase();\n return first === \"https\" ? \"https\" : \"http\";\n}\n\nexport async function startNodeRequestServer(\n options: StartNodeRequestServerOptions,\n): Promise<{ close(): Promise<void>; server: Server; url: string }> {\n const server = createServer(async (incoming, outgoing) => {\n const startedAt = logNow();\n const fallbackRequestFields = {\n method: incoming.method ?? \"GET\",\n path: nodeRequestPath(incoming.url),\n runtime: \"node\" as const,\n };\n\n try {\n const fallbackHost = `${options.hostname ?? \"127.0.0.1\"}:${options.port}`;\n const host = (options.resolveHost ?? defaultResolveRequestHost)({\n allowedHosts: options.allowedHosts,\n fallbackHost,\n hostPolicy: options.hostPolicy,\n rawHost: incoming.headers.host,\n });\n const protocol = resolveNodeRequestProtocol({\n encrypted: (incoming.socket as { encrypted?: boolean }).encrypted === true,\n forwardedProto: incoming.headers[\"x-forwarded-proto\"],\n trustForwardedProto: options.trustForwardedProto,\n });\n const request = nodeRequestToWebRequest(incoming, `${protocol}://${host}`);\n const logFields = requestLogFields(request, \"node\");\n emitRouterLog(options.logger, \"info\", {\n ...logFields,\n type: \"router:request:start\",\n });\n const response = await options.render(request);\n emitRouterLog(options.logger, \"info\", {\n ...logFields,\n durationMs: logDurationMs(startedAt),\n status: response.status,\n type: \"router:request:end\",\n });\n\n await sendResponse(outgoing, response);\n } catch (error) {\n // Log the full stack to stderr for operator visibility; never put\n // it in the response body where attackers can scrape it.\n emitRouterLog(options.logger, \"error\", {\n ...fallbackRequestFields,\n durationMs: logDurationMs(startedAt),\n error: logError(error),\n type: \"router:request:error\",\n });\n if (options.logger === undefined) {\n console.error(\"[mreact] startServer request failed:\", error);\n }\n const payload = options.errorHandler\n ? options.errorHandler(error)\n : { body: \"Internal Server Error\", status: 500 };\n outgoing.statusCode = payload.status;\n outgoing.setHeader(\n \"content-type\",\n payload.headers?.[\"content-type\"] ?? \"text/plain; charset=utf-8\",\n );\n for (const [name, value] of Object.entries(payload.headers ?? {})) {\n if (name.toLowerCase() === \"content-type\") continue;\n outgoing.setHeader(name, value);\n }\n outgoing.end(payload.body);\n }\n });\n\n if (options.onUpgrade !== undefined) {\n server.on(\"upgrade\", options.onUpgrade);\n }\n\n await new Promise<void>((resolve) =>\n server.listen(options.port, options.hostname ?? \"127.0.0.1\", resolve),\n );\n const address = server.address();\n const port = typeof address === \"object\" && address !== null ? address.port : options.port;\n\n return {\n server,\n url: `http://${options.hostname ?? \"127.0.0.1\"}:${port}`,\n close: () =>\n new Promise<void>((resolve, reject) =>\n server.close((error) => (error ? reject(error) : resolve())),\n ),\n };\n}\n\nfunction defaultResolveRequestHost(options: {\n allowedHosts?: readonly string[] | undefined;\n fallbackHost: string;\n hostPolicy?: \"strict\" | \"trusted-proxy\" | undefined;\n rawHost: string | undefined;\n}): string {\n const raw = options.rawHost;\n if (raw === undefined || raw === \"\") return options.fallbackHost;\n if (options.allowedHosts === undefined) {\n return options.hostPolicy === \"strict\" ? options.fallbackHost : raw;\n }\n return options.allowedHosts.includes(raw) ? raw : options.fallbackHost;\n}\n"]}
1
+ {"version":3,"file":"node-server.js","sourceRoot":"","sources":["../src/node-server.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type Server } from \"node:http\";\nimport { nodeRequestToWebRequest, sendResponse } from \"./http.js\";\nimport {\n emitRouterLog,\n logDurationMs,\n logError,\n logNow,\n nodeRequestPath,\n requestLogFields,\n type AppRouterLogger,\n} from \"./logger.js\";\nimport {\n assertValidHttpUpgradeOriginPolicy,\n closeServerWithUpgrades,\n createManagedHttpUpgradeLifecycle,\n validateHttpUpgradeOrigin,\n type HttpUpgradeOriginPolicy,\n type HttpUpgradeOriginValidation,\n type ManagedHttpUpgradeHandler,\n} from \"./upgrade.js\";\n\nexport interface StartNodeRequestServerOptions {\n allowedHosts?: readonly string[] | undefined;\n errorHandler?:\n | ((error: unknown) => {\n body: string;\n status: number;\n headers?: Record<string, string>;\n })\n | undefined;\n hostname?: string | undefined;\n hostPolicy?: \"strict\" | \"trusted-proxy\" | undefined;\n logger?: AppRouterLogger | undefined;\n onUpgrade?: ManagedHttpUpgradeHandler | undefined;\n port: number;\n render(request: Request): Promise<Response>;\n resolveHost?:\n | ((options: {\n allowedHosts?: readonly string[] | undefined;\n fallbackHost: string;\n hostPolicy?: \"strict\" | \"trusted-proxy\" | undefined;\n rawHost: string | undefined;\n }) => string)\n | undefined;\n trustForwardedProto?: boolean | undefined;\n upgradeCloseTimeoutMs?: number | undefined;\n upgradeDecisionTimeoutMs?: number | undefined;\n upgradeOriginPolicy?: HttpUpgradeOriginPolicy | undefined;\n}\n\nexport function resolveNodeRequestProtocol(options: {\n encrypted: boolean;\n forwardedProto: string | readonly string[] | undefined;\n trustForwardedProto?: boolean | undefined;\n}): \"http\" | \"https\" {\n if (options.encrypted) {\n return \"https\";\n }\n\n if (options.trustForwardedProto !== true) {\n return \"http\";\n }\n\n const forwarded = Array.isArray(options.forwardedProto)\n ? options.forwardedProto[0]\n : options.forwardedProto;\n const first = forwarded?.split(\",\", 1)[0]?.trim().toLowerCase();\n return first === \"https\" ? \"https\" : \"http\";\n}\n\nexport async function startNodeRequestServer(\n options: StartNodeRequestServerOptions,\n): Promise<{ close(): Promise<void>; server: Server; url: string }> {\n const upgradeCloseTimeoutMs = finiteNonNegativeTimeout(\n options.upgradeCloseTimeoutMs,\n 1_000,\n \"upgradeCloseTimeoutMs\",\n );\n const upgradeDecisionTimeoutMs = finiteNonNegativeTimeout(\n options.upgradeDecisionTimeoutMs,\n 1_000,\n \"upgradeDecisionTimeoutMs\",\n );\n assertValidHttpUpgradeOriginPolicy(options.upgradeOriginPolicy);\n let listeningPort = options.port;\n const server = createServer(async (incoming, outgoing) => {\n const startedAt = logNow();\n const fallbackRequestFields = {\n method: incoming.method ?? \"GET\",\n path: nodeRequestPath(incoming.url),\n runtime: \"node\" as const,\n };\n\n try {\n const fallbackHost = formatNodeAuthority(options.hostname ?? \"127.0.0.1\", options.port);\n const host = (options.resolveHost ?? defaultResolveRequestHost)({\n allowedHosts: options.allowedHosts,\n fallbackHost,\n hostPolicy: options.hostPolicy,\n rawHost: incoming.headers.host,\n });\n const protocol = resolveNodeRequestProtocol({\n encrypted: (incoming.socket as { encrypted?: boolean }).encrypted === true,\n forwardedProto: incoming.headers[\"x-forwarded-proto\"],\n trustForwardedProto: options.trustForwardedProto,\n });\n const request = nodeRequestToWebRequest(incoming, `${protocol}://${host}`, outgoing);\n const logFields = requestLogFields(request, \"node\");\n emitRouterLog(options.logger, \"info\", {\n ...logFields,\n type: \"router:request:start\",\n });\n const response = await options.render(request);\n emitRouterLog(options.logger, \"info\", {\n ...logFields,\n durationMs: logDurationMs(startedAt),\n status: response.status,\n type: \"router:request:end\",\n });\n\n await sendResponse(outgoing, response);\n } catch (error) {\n // Log the full stack to stderr for operator visibility; never put\n // it in the response body where attackers can scrape it.\n emitRouterLog(options.logger, \"error\", {\n ...fallbackRequestFields,\n durationMs: logDurationMs(startedAt),\n error: logError(error),\n type: \"router:request:error\",\n });\n if (options.logger === undefined) {\n console.error(\"[mreact] startServer request failed:\", error);\n }\n const payload = options.errorHandler\n ? options.errorHandler(error)\n : { body: \"Internal Server Error\", status: 500 };\n outgoing.statusCode = payload.status;\n outgoing.setHeader(\n \"content-type\",\n payload.headers?.[\"content-type\"] ?? \"text/plain; charset=utf-8\",\n );\n for (const [name, value] of Object.entries(payload.headers ?? {})) {\n if (name.toLowerCase() === \"content-type\") continue;\n outgoing.setHeader(name, value);\n }\n outgoing.end(payload.body);\n }\n });\n\n const upgradeLifecycle =\n options.onUpgrade === undefined\n ? undefined\n : createManagedHttpUpgradeLifecycle({\n decisionTimeoutMs: upgradeDecisionTimeoutMs,\n handler: options.onUpgrade,\n isOriginAllowed: (request) =>\n validateNodeUpgradeOrigin(request, {\n ...options,\n listeningPort,\n }),\n logger: options.logger,\n });\n if (upgradeLifecycle !== undefined) {\n server.on(\"upgrade\", upgradeLifecycle.handle);\n }\n\n await new Promise<void>((resolve) =>\n server.listen(options.port, options.hostname ?? \"127.0.0.1\", resolve),\n );\n const address = server.address();\n const port = typeof address === \"object\" && address !== null ? address.port : options.port;\n listeningPort = port;\n let closePromise: Promise<void> | undefined;\n\n return {\n server,\n url: `http://${formatNodeAuthority(options.hostname ?? \"127.0.0.1\", port)}`,\n close: () => {\n closePromise ??=\n upgradeLifecycle === undefined\n ? new Promise<void>((resolve, reject) =>\n server.close((error) => (error ? reject(error) : resolve())),\n )\n : closeServerWithUpgrades({\n lifecycle: upgradeLifecycle,\n server,\n timeoutMs: upgradeCloseTimeoutMs,\n });\n return closePromise;\n },\n };\n}\n\nfunction validateNodeUpgradeOrigin(\n request: import(\"node:http\").IncomingMessage,\n options: StartNodeRequestServerOptions & { listeningPort: number },\n): HttpUpgradeOriginValidation {\n const policy = options.upgradeOriginPolicy ?? \"same-origin\";\n if (policy === \"unchecked\") {\n return { ok: true, origin: request.headers.origin };\n }\n if (typeof policy === \"object\") {\n return validateHttpUpgradeOrigin(request, policy);\n }\n\n const fallbackHost = formatNodeAuthority(options.hostname ?? \"127.0.0.1\", options.listeningPort);\n const host = (options.resolveHost ?? defaultResolveRequestHost)({\n allowedHosts: options.allowedHosts,\n fallbackHost,\n hostPolicy: options.hostPolicy,\n rawHost: request.headers.host,\n });\n const protocol = resolveNodeRequestProtocol({\n encrypted: (request.socket as { encrypted?: boolean }).encrypted === true,\n forwardedProto: request.headers[\"x-forwarded-proto\"],\n trustForwardedProto: options.trustForwardedProto,\n });\n try {\n return validateHttpUpgradeOrigin(request, { allowedOrigins: [`${protocol}://${host}`] });\n } catch {\n return { ok: false, reason: \"malformed-origin\" };\n }\n}\n\nfunction formatNodeAuthority(hostname: string, port: number): string {\n const host = hostname.includes(\":\") && !hostname.startsWith(\"[\") ? `[${hostname}]` : hostname;\n return `${host}:${port}`;\n}\n\nfunction finiteNonNegativeTimeout(\n value: number | undefined,\n fallback: number,\n name: string,\n): number {\n const timeout = value ?? fallback;\n if (\n !Number.isFinite(timeout) ||\n timeout < 0 ||\n !Number.isSafeInteger(timeout) ||\n timeout > 2_147_483_647\n ) {\n throw new TypeError(\n `${name} must be a finite non-negative safe integer no greater than 2147483647.`,\n );\n }\n return timeout;\n}\n\nfunction defaultResolveRequestHost(options: {\n allowedHosts?: readonly string[] | undefined;\n fallbackHost: string;\n hostPolicy?: \"strict\" | \"trusted-proxy\" | undefined;\n rawHost: string | undefined;\n}): string {\n const raw = options.rawHost;\n if (raw === undefined || raw === \"\") return options.fallbackHost;\n if (options.allowedHosts === undefined) {\n return options.hostPolicy === \"strict\" ? options.fallbackHost : raw;\n }\n return options.allowedHosts.includes(raw) ? raw : options.fallbackHost;\n}\n"]}
@@ -1,5 +1,21 @@
1
1
  import type { BuiltPrerenderedRoute } from "./build.js";
2
- export declare const PRERENDERED_ROUTE_SCHEMA_VERSION = 2;
2
+ export declare const PRERENDERED_ROUTE_SCHEMA_VERSION = 4;
3
3
  export declare function isCurrentPrerenderedRoute(value: unknown): value is BuiltPrerenderedRoute;
4
+ /**
5
+ * Returns a navigation variant only after validating its route marker.
6
+ *
7
+ * Stored entries are stable objects during a runtime's lifetime, so the
8
+ * marker scan is cached by identity. Document requests never call this
9
+ * function and therefore never inspect navigation HTML.
10
+ */
11
+ export declare function validatedPrerenderedNavigationHtml(entry: BuiltPrerenderedRoute): string | undefined;
12
+ /**
13
+ * Adds a regenerated navigation variant only when it satisfies the marker
14
+ * contract. Invalid navigation output must not replace a valid document.
15
+ */
16
+ export declare function mergePrerenderedNavigationHtml(entry: BuiltPrerenderedRoute, navigationHtml: string): BuiltPrerenderedRoute;
4
17
  export declare function isVisitorDependentResponse(response: Response): boolean;
18
+ export declare function protectNonceBearingResponse(response: Response): Response;
19
+ export declare function storedPrerenderedRouteHeaders(headers: Headers): Record<string, string>;
20
+ export declare function replayedPrerenderedRouteHeaders(entry: BuiltPrerenderedRoute, request: Request): Headers;
5
21
  //# sourceMappingURL=prerender-entry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prerender-entry.d.ts","sourceRoot":"","sources":["../src/prerender-entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAElD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAgBxF;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAEtE"}
1
+ {"version":3,"file":"prerender-entry.d.ts","sourceRoot":"","sources":["../src/prerender-entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAIxD,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAIlD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAmBxF;AAED;;;;;;GAMG;AACH,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,qBAAqB,GAC3B,MAAM,GAAG,SAAS,CAWpB;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,qBAAqB,EAC5B,cAAc,EAAE,MAAM,GACrB,qBAAqB,CAEvB;AAkBD,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAEtE;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAaxE;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUtF;AAED,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,qBAAqB,EAC5B,OAAO,EAAE,OAAO,GACf,OAAO,CAYT"}
@@ -1,4 +1,7 @@
1
- export const PRERENDERED_ROUTE_SCHEMA_VERSION = 2;
1
+ import { responseHeadersContainCspNonce } from "./csp.js";
2
+ import { hasNavigationRouteMarker } from "./navigation-marker.js";
3
+ export const PRERENDERED_ROUTE_SCHEMA_VERSION = 4;
4
+ const validatedNavigationHtmlByEntry = new WeakMap();
2
5
  export function isCurrentPrerenderedRoute(value) {
3
6
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
4
7
  return false;
@@ -7,15 +10,101 @@ export function isCurrentPrerenderedRoute(value) {
7
10
  return (entry.schemaVersion === PRERENDERED_ROUTE_SCHEMA_VERSION &&
8
11
  isStringRecord(entry.headers) &&
9
12
  isShareableHeaderRecord(entry.headers) &&
13
+ hasRequiredNavigationVary(entry.headers) &&
14
+ !hasStoredHstsHeader(entry.headers) &&
15
+ isCanonicalHstsHeader(entry.strictTransportSecurity) &&
10
16
  typeof entry.html === "string" &&
11
17
  typeof entry.status === "number" &&
12
18
  Number.isInteger(entry.status) &&
13
19
  entry.status >= 100 &&
14
20
  entry.status <= 599);
15
21
  }
22
+ /**
23
+ * Returns a navigation variant only after validating its route marker.
24
+ *
25
+ * Stored entries are stable objects during a runtime's lifetime, so the
26
+ * marker scan is cached by identity. Document requests never call this
27
+ * function and therefore never inspect navigation HTML.
28
+ */
29
+ export function validatedPrerenderedNavigationHtml(entry) {
30
+ const cached = validatedNavigationHtmlByEntry.get(entry);
31
+ if (cached !== undefined) {
32
+ return cached === null ? undefined : cached;
33
+ }
34
+ const candidate = entry.navigationHtml;
35
+ const validated = typeof candidate === "string" && hasNavigationRouteMarker(candidate) ? candidate : null;
36
+ validatedNavigationHtmlByEntry.set(entry, validated);
37
+ return validated === null ? undefined : validated;
38
+ }
39
+ /**
40
+ * Adds a regenerated navigation variant only when it satisfies the marker
41
+ * contract. Invalid navigation output must not replace a valid document.
42
+ */
43
+ export function mergePrerenderedNavigationHtml(entry, navigationHtml) {
44
+ return hasNavigationRouteMarker(navigationHtml) ? { ...entry, navigationHtml } : entry;
45
+ }
46
+ function hasStoredHstsHeader(headers) {
47
+ try {
48
+ return new Headers(headers).has("strict-transport-security");
49
+ }
50
+ catch {
51
+ return true;
52
+ }
53
+ }
54
+ function isCanonicalHstsHeader(value) {
55
+ return (value === undefined ||
56
+ (typeof value === "string" &&
57
+ /^max-age=(?:0|[1-9][0-9]*)(?:; includeSubDomains)?(?:; preload)?$/.test(value)));
58
+ }
16
59
  export function isVisitorDependentResponse(response) {
17
60
  return isVisitorDependentHeaders(response.headers);
18
61
  }
62
+ export function protectNonceBearingResponse(response) {
63
+ if (!responseHeadersContainCspNonce(response.headers)) {
64
+ return response;
65
+ }
66
+ const headers = new Headers(response.headers);
67
+ headers.set("cache-control", "private, no-store");
68
+ headers.set("x-mreact-cache", "DYNAMIC");
69
+ return new Response(response.body, {
70
+ headers,
71
+ status: response.status,
72
+ statusText: response.statusText,
73
+ });
74
+ }
75
+ export function storedPrerenderedRouteHeaders(headers) {
76
+ const stored = {};
77
+ headers.forEach((value, key) => {
78
+ if (key !== "strict-transport-security") {
79
+ stored[key] = value;
80
+ }
81
+ });
82
+ return stored;
83
+ }
84
+ export function replayedPrerenderedRouteHeaders(entry, request) {
85
+ const headers = new Headers(entry.headers);
86
+ if (!hasNavigationVary(headers)) {
87
+ headers.append("vary", "x-mreact-navigation");
88
+ }
89
+ if (entry.strictTransportSecurity !== undefined && request.url.startsWith("https://")) {
90
+ headers.set("strict-transport-security", entry.strictTransportSecurity);
91
+ }
92
+ return headers;
93
+ }
94
+ function hasRequiredNavigationVary(headers) {
95
+ try {
96
+ return hasNavigationVary(new Headers(headers));
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ }
102
+ function hasNavigationVary(headers) {
103
+ return (headers
104
+ .get("vary")
105
+ ?.split(",")
106
+ .some((value) => value.trim().toLowerCase() === "x-mreact-navigation") === true);
107
+ }
19
108
  function isShareableHeaderRecord(headers) {
20
109
  try {
21
110
  return !isVisitorDependentHeaders(new Headers(headers));
@@ -26,10 +115,16 @@ function isShareableHeaderRecord(headers) {
26
115
  }
27
116
  function isVisitorDependentHeaders(headers) {
28
117
  const cacheControl = headers.get("cache-control") ?? "";
29
- const forbidsSharedStorage = cacheControl.split(",").some((directive) => /^(?:private|no-cache|no-store)(?:=|$)/i.test(directive.trim()));
118
+ const vary = headers.get("vary");
119
+ const hasVisitorDependentVary = vary !== null &&
120
+ vary.split(",").some((value) => value.trim().toLowerCase() !== "x-mreact-navigation");
121
+ const forbidsSharedStorage = cacheControl
122
+ .split(",")
123
+ .some((directive) => /^(?:private|no-cache|no-store)(?:=|$)/i.test(directive.trim()));
30
124
  return (headers.get("x-mreact-cache")?.toUpperCase() === "DYNAMIC" ||
31
125
  headers.has("set-cookie") ||
32
- headers.has("vary") ||
126
+ responseHeadersContainCspNonce(headers) ||
127
+ hasVisitorDependentVary ||
33
128
  forbidsSharedStorage);
34
129
  }
35
130
  function isStringRecord(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"prerender-entry.js","sourceRoot":"","sources":["../src/prerender-entry.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC;AAElD,MAAM,UAAU,yBAAyB,CAAC,KAAc;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,KAAuC,CAAC;IACtD,OAAO,CACL,KAAK,CAAC,aAAa,KAAK,gCAAgC;QACxD,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC;QAC7B,uBAAuB,CAAC,KAAK,CAAC,OAAO,CAAC;QACtC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAChC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;QAC9B,KAAK,CAAC,MAAM,IAAI,GAAG;QACnB,KAAK,CAAC,MAAM,IAAI,GAAG,CACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAkB;IAC3D,OAAO,yBAAyB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,uBAAuB,CAAC,OAA+B;IAC9D,IAAI,CAAC;QACH,OAAO,CAAC,yBAAyB,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,yBAAyB,CAAC,OAAgB;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,oBAAoB,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CACtE,wCAAwC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAChE,CAAC;IAEF,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,WAAW,EAAE,KAAK,SAAS;QAC1D,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;QACnB,oBAAoB,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CACjE,CAAC;AACJ,CAAC","sourcesContent":["import type { BuiltPrerenderedRoute } from \"./build.js\";\n\nexport const PRERENDERED_ROUTE_SCHEMA_VERSION = 2;\n\nexport function isCurrentPrerenderedRoute(value: unknown): value is BuiltPrerenderedRoute {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n\n const entry = value as Partial<BuiltPrerenderedRoute>;\n return (\n entry.schemaVersion === PRERENDERED_ROUTE_SCHEMA_VERSION &&\n isStringRecord(entry.headers) &&\n isShareableHeaderRecord(entry.headers) &&\n typeof entry.html === \"string\" &&\n typeof entry.status === \"number\" &&\n Number.isInteger(entry.status) &&\n entry.status >= 100 &&\n entry.status <= 599\n );\n}\n\nexport function isVisitorDependentResponse(response: Response): boolean {\n return isVisitorDependentHeaders(response.headers);\n}\n\nfunction isShareableHeaderRecord(headers: Record<string, string>): boolean {\n try {\n return !isVisitorDependentHeaders(new Headers(headers));\n } catch {\n return false;\n }\n}\n\nfunction isVisitorDependentHeaders(headers: Headers): boolean {\n const cacheControl = headers.get(\"cache-control\") ?? \"\";\n const forbidsSharedStorage = cacheControl.split(\",\").some((directive) =>\n /^(?:private|no-cache|no-store)(?:=|$)/i.test(directive.trim()),\n );\n\n return (\n headers.get(\"x-mreact-cache\")?.toUpperCase() === \"DYNAMIC\" ||\n headers.has(\"set-cookie\") ||\n headers.has(\"vary\") ||\n forbidsSharedStorage\n );\n}\n\nfunction isStringRecord(value: unknown): value is Record<string, string> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.values(value).every((entry) => typeof entry === \"string\")\n );\n}\n"]}
1
+ {"version":3,"file":"prerender-entry.js","sourceRoot":"","sources":["../src/prerender-entry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAElE,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,CAAC;AAElD,MAAM,8BAA8B,GAAG,IAAI,OAAO,EAAyB,CAAC;AAE5E,MAAM,UAAU,yBAAyB,CAAC,KAAc;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,KAAuC,CAAC;IACtD,OAAO,CACL,KAAK,CAAC,aAAa,KAAK,gCAAgC;QACxD,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC;QAC7B,uBAAuB,CAAC,KAAK,CAAC,OAAO,CAAC;QACtC,yBAAyB,CAAC,KAAK,CAAC,OAAO,CAAC;QACxC,CAAC,mBAAmB,CAAC,KAAK,CAAC,OAAO,CAAC;QACnC,qBAAqB,CAAC,KAAK,CAAC,uBAAuB,CAAC;QACpD,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;QAChC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;QAC9B,KAAK,CAAC,MAAM,IAAI,GAAG;QACnB,KAAK,CAAC,MAAM,IAAI,GAAG,CACpB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kCAAkC,CAChD,KAA4B;IAE5B,MAAM,MAAM,GAAG,8BAA8B,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9C,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,cAAc,CAAC;IACvC,MAAM,SAAS,GACb,OAAO,SAAS,KAAK,QAAQ,IAAI,wBAAwB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1F,8BAA8B,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACrD,OAAO,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAC5C,KAA4B,EAC5B,cAAsB;IAEtB,OAAO,wBAAwB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AACzF,CAAC;AAED,SAAS,mBAAmB,CAAC,OAA+B;IAC1D,IAAI,CAAC;QACH,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc;IAC3C,OAAO,CACL,KAAK,KAAK,SAAS;QACnB,CAAC,OAAO,KAAK,KAAK,QAAQ;YACxB,mEAAmE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CACnF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAkB;IAC3D,OAAO,yBAAyB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,QAAkB;IAC5D,IAAI,CAAC,8BAA8B,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;IACzC,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QACjC,OAAO;QACP,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;KAChC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,OAAgB;IAC5D,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC7B,IAAI,GAAG,KAAK,2BAA2B,EAAE,CAAC;YACxC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,+BAA+B,CAC7C,KAA4B,EAC5B,OAAgB;IAEhB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE3C,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,KAAK,CAAC,uBAAuB,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACtF,OAAO,CAAC,GAAG,CAAC,2BAA2B,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,yBAAyB,CAAC,OAA+B;IAChE,IAAI,CAAC;QACH,OAAO,iBAAiB,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAgB;IACzC,OAAO,CACL,OAAO;SACJ,GAAG,CAAC,MAAM,CAAC;QACZ,EAAE,KAAK,CAAC,GAAG,CAAC;SACX,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,qBAAqB,CAAC,KAAK,IAAI,CAClF,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,OAA+B;IAC9D,IAAI,CAAC;QACH,OAAO,CAAC,yBAAyB,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,yBAAyB,CAAC,OAAgB;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,uBAAuB,GAC3B,IAAI,KAAK,IAAI;QACb,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,qBAAqB,CAAC,CAAC;IACxF,MAAM,oBAAoB,GAAG,YAAY;SACtC,KAAK,CAAC,GAAG,CAAC;SACV,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,wCAAwC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAExF,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,WAAW,EAAE,KAAK,SAAS;QAC1D,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QACzB,8BAA8B,CAAC,OAAO,CAAC;QACvC,uBAAuB;QACvB,oBAAoB,CACrB,CAAC;AACJ,CAAC;AAED,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CACjE,CAAC;AACJ,CAAC","sourcesContent":["import type { BuiltPrerenderedRoute } from \"./build.js\";\nimport { responseHeadersContainCspNonce } from \"./csp.js\";\nimport { hasNavigationRouteMarker } from \"./navigation-marker.js\";\n\nexport const PRERENDERED_ROUTE_SCHEMA_VERSION = 4;\n\nconst validatedNavigationHtmlByEntry = new WeakMap<object, string | null>();\n\nexport function isCurrentPrerenderedRoute(value: unknown): value is BuiltPrerenderedRoute {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return false;\n }\n\n const entry = value as Partial<BuiltPrerenderedRoute>;\n return (\n entry.schemaVersion === PRERENDERED_ROUTE_SCHEMA_VERSION &&\n isStringRecord(entry.headers) &&\n isShareableHeaderRecord(entry.headers) &&\n hasRequiredNavigationVary(entry.headers) &&\n !hasStoredHstsHeader(entry.headers) &&\n isCanonicalHstsHeader(entry.strictTransportSecurity) &&\n typeof entry.html === \"string\" &&\n typeof entry.status === \"number\" &&\n Number.isInteger(entry.status) &&\n entry.status >= 100 &&\n entry.status <= 599\n );\n}\n\n/**\n * Returns a navigation variant only after validating its route marker.\n *\n * Stored entries are stable objects during a runtime's lifetime, so the\n * marker scan is cached by identity. Document requests never call this\n * function and therefore never inspect navigation HTML.\n */\nexport function validatedPrerenderedNavigationHtml(\n entry: BuiltPrerenderedRoute,\n): string | undefined {\n const cached = validatedNavigationHtmlByEntry.get(entry);\n if (cached !== undefined) {\n return cached === null ? undefined : cached;\n }\n\n const candidate = entry.navigationHtml;\n const validated =\n typeof candidate === \"string\" && hasNavigationRouteMarker(candidate) ? candidate : null;\n validatedNavigationHtmlByEntry.set(entry, validated);\n return validated === null ? undefined : validated;\n}\n\n/**\n * Adds a regenerated navigation variant only when it satisfies the marker\n * contract. Invalid navigation output must not replace a valid document.\n */\nexport function mergePrerenderedNavigationHtml(\n entry: BuiltPrerenderedRoute,\n navigationHtml: string,\n): BuiltPrerenderedRoute {\n return hasNavigationRouteMarker(navigationHtml) ? { ...entry, navigationHtml } : entry;\n}\n\nfunction hasStoredHstsHeader(headers: Record<string, string>): boolean {\n try {\n return new Headers(headers).has(\"strict-transport-security\");\n } catch {\n return true;\n }\n}\n\nfunction isCanonicalHstsHeader(value: unknown): value is string | undefined {\n return (\n value === undefined ||\n (typeof value === \"string\" &&\n /^max-age=(?:0|[1-9][0-9]*)(?:; includeSubDomains)?(?:; preload)?$/.test(value))\n );\n}\n\nexport function isVisitorDependentResponse(response: Response): boolean {\n return isVisitorDependentHeaders(response.headers);\n}\n\nexport function protectNonceBearingResponse(response: Response): Response {\n if (!responseHeadersContainCspNonce(response.headers)) {\n return response;\n }\n\n const headers = new Headers(response.headers);\n headers.set(\"cache-control\", \"private, no-store\");\n headers.set(\"x-mreact-cache\", \"DYNAMIC\");\n return new Response(response.body, {\n headers,\n status: response.status,\n statusText: response.statusText,\n });\n}\n\nexport function storedPrerenderedRouteHeaders(headers: Headers): Record<string, string> {\n const stored: Record<string, string> = {};\n\n headers.forEach((value, key) => {\n if (key !== \"strict-transport-security\") {\n stored[key] = value;\n }\n });\n\n return stored;\n}\n\nexport function replayedPrerenderedRouteHeaders(\n entry: BuiltPrerenderedRoute,\n request: Request,\n): Headers {\n const headers = new Headers(entry.headers);\n\n if (!hasNavigationVary(headers)) {\n headers.append(\"vary\", \"x-mreact-navigation\");\n }\n\n if (entry.strictTransportSecurity !== undefined && request.url.startsWith(\"https://\")) {\n headers.set(\"strict-transport-security\", entry.strictTransportSecurity);\n }\n\n return headers;\n}\n\nfunction hasRequiredNavigationVary(headers: Record<string, string>): boolean {\n try {\n return hasNavigationVary(new Headers(headers));\n } catch {\n return false;\n }\n}\n\nfunction hasNavigationVary(headers: Headers): boolean {\n return (\n headers\n .get(\"vary\")\n ?.split(\",\")\n .some((value) => value.trim().toLowerCase() === \"x-mreact-navigation\") === true\n );\n}\n\nfunction isShareableHeaderRecord(headers: Record<string, string>): boolean {\n try {\n return !isVisitorDependentHeaders(new Headers(headers));\n } catch {\n return false;\n }\n}\n\nfunction isVisitorDependentHeaders(headers: Headers): boolean {\n const cacheControl = headers.get(\"cache-control\") ?? \"\";\n const vary = headers.get(\"vary\");\n const hasVisitorDependentVary =\n vary !== null &&\n vary.split(\",\").some((value) => value.trim().toLowerCase() !== \"x-mreact-navigation\");\n const forbidsSharedStorage = cacheControl\n .split(\",\")\n .some((directive) => /^(?:private|no-cache|no-store)(?:=|$)/i.test(directive.trim()));\n\n return (\n headers.get(\"x-mreact-cache\")?.toUpperCase() === \"DYNAMIC\" ||\n headers.has(\"set-cookie\") ||\n responseHeadersContainCspNonce(headers) ||\n hasVisitorDependentVary ||\n forbidsSharedStorage\n );\n}\n\nfunction isStringRecord(value: unknown): value is Record<string, string> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.values(value).every((entry) => typeof entry === \"string\")\n );\n}\n"]}
package/dist/render.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ServerOutputMode, TransformOutput } from "@reckona/mreact-shared/compiler-contract";
2
- import { type QueryClient } from "@reckona/mreact-query";
2
+ import { type DehydrateOptions, type QueryClient } from "@reckona/mreact-query";
3
3
  import { type ClientRouteInferenceCache } from "./client-route-inference.js";
4
4
  import type { AppRoute, MatchedRoute, RouteMatcher } from "./routes.js";
5
5
  import { type AppRouterServerActionOptions, type PreparedFormActionReference } from "./actions.js";
@@ -31,6 +31,7 @@ export interface RenderAppRequestOptions {
31
31
  clientStylesByFile?: ReadonlyMap<string, readonly string[]>;
32
32
  clientStyles?: ReadonlyMap<string, readonly string[]>;
33
33
  define?: UserConfig["define"] | undefined;
34
+ dehydrateOptions?: DehydrateOptions | undefined;
34
35
  env?: unknown;
35
36
  importPolicy?: AppRouterImportPolicy | undefined;
36
37
  instrumentation?: RouterInstrumentation | undefined;
@@ -46,6 +47,7 @@ export interface RenderAppRequestOptions {
46
47
  routeMatcher?: RouteMatcher | undefined;
47
48
  routes?: readonly AppRoute[] | undefined;
48
49
  serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
50
+ serverRenderArtifactLoader?: AppRouterServerRenderArtifactLoader | undefined;
49
51
  serverModuleCacheVersion?: string | undefined;
50
52
  devServerModuleCacheVersion?: string | undefined;
51
53
  dev?: boolean | undefined;
@@ -57,6 +59,14 @@ export interface RenderAppRequestOptions {
57
59
  vitePlugins?: readonly PluginOption[] | undefined;
58
60
  }
59
61
  export interface RenderAppRequestRuntimeOptions extends RenderAppRequestOptions {
62
+ /**
63
+ * Wraps a server-only page with build-time variant capture comments.
64
+ *
65
+ * This is an in-process render signal. It must not be derived from request
66
+ * headers because network clients are not allowed to change response shape
67
+ * outside the route-cache key.
68
+ */
69
+ prerenderVariantCapture?: boolean | undefined;
60
70
  /**
61
71
  * Receives whether the render depended on the incoming request headers.
62
72
  *
@@ -69,8 +79,8 @@ export interface RenderAppRequestRuntimeOptions extends RenderAppRequestOptions
69
79
  */
70
80
  renderSignals?: {
71
81
  headerDependent: () => boolean;
82
+ strictTransportSecurity: () => string | undefined;
72
83
  } | undefined;
73
- serverRenderArtifactLoader?: AppRouterServerRenderArtifactLoader | undefined;
74
84
  }
75
85
  export interface AppRouterRenderPreload {
76
86
  promise: Promise<void>;
@@ -125,6 +135,10 @@ export declare function resolveAppRouterMiddleware(options: {
125
135
  vitePlugins?: readonly PluginOption[] | undefined;
126
136
  }): Promise<AppRouterMiddlewareResult>;
127
137
  export declare function resolveAppRouterResponseHook(options: Pick<RenderAppRequestOptions, "appDir" | "define" | "devServerModuleCacheVersion" | "importPolicy" | "onResponse" | "serverModules" | "serverModuleCacheVersion" | "serverSourceFiles" | "vitePlugins">): Promise<AppRouterResponseHook | undefined>;
138
+ export declare function prerenderVariantMarkerParts(routePath: string): {
139
+ prefix: string;
140
+ suffix: string;
141
+ };
128
142
  export declare function bundleMiddlewareModuleCode(options: {
129
143
  appDir: string;
130
144
  code: string;
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}