@rshono/core 1.0.0-rc.2 → 1.0.0-rc.21

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 (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +348 -158
  3. package/bin/rshono.mjs +3 -4
  4. package/dist/builder/env-shadow-loader.cjs +123 -8
  5. package/dist/builder/page-entry-loader.cjs +28 -1
  6. package/dist/builder/page-files.d.ts +0 -1
  7. package/dist/builder/page-files.js +7 -3
  8. package/dist/builder/page-files.js.map +1 -1
  9. package/dist/builder/public-env.d.ts +7 -1
  10. package/dist/builder/public-env.js +7 -0
  11. package/dist/builder/public-env.js.map +1 -1
  12. package/dist/builder/react-versions.d.ts +12 -0
  13. package/dist/builder/react-versions.js +74 -0
  14. package/dist/builder/react-versions.js.map +1 -0
  15. package/dist/builder/rspack-config.d.ts +13 -4
  16. package/dist/builder/rspack-config.js +136 -53
  17. package/dist/builder/rspack-config.js.map +1 -1
  18. package/dist/builder/server-only-imports.d.ts +32 -0
  19. package/dist/builder/server-only-imports.js +51 -0
  20. package/dist/builder/server-only-imports.js.map +1 -0
  21. package/dist/cli/build.d.ts +2 -3
  22. package/dist/cli/build.js +51 -13
  23. package/dist/cli/build.js.map +1 -1
  24. package/dist/cli/dev.d.ts +2 -3
  25. package/dist/cli/dev.js +149 -45
  26. package/dist/cli/dev.js.map +1 -1
  27. package/dist/cli/exit.d.ts +12 -0
  28. package/dist/cli/exit.js +16 -0
  29. package/dist/cli/exit.js.map +1 -0
  30. package/dist/cli/index.d.ts +0 -1
  31. package/dist/cli/index.js +91 -30
  32. package/dist/cli/index.js.map +1 -1
  33. package/dist/cli/start.d.ts +0 -1
  34. package/dist/cli/start.js +15 -18
  35. package/dist/cli/start.js.map +1 -1
  36. package/dist/config.d.ts +72 -78
  37. package/dist/config.js +17 -1
  38. package/dist/config.js.map +1 -1
  39. package/dist/deploy/aws-lambda/runtime.d.ts +4 -7
  40. package/dist/deploy/aws-lambda/runtime.js +5 -8
  41. package/dist/deploy/aws-lambda/runtime.js.map +1 -1
  42. package/dist/deploy/build-marker.d.ts +9 -6
  43. package/dist/deploy/build-marker.js +8 -4
  44. package/dist/deploy/build-marker.js.map +1 -1
  45. package/dist/deploy/cloudflare/build.d.ts +0 -1
  46. package/dist/deploy/cloudflare/build.js +17 -13
  47. package/dist/deploy/cloudflare/build.js.map +1 -1
  48. package/dist/deploy/cloudflare/runtime.d.ts +2 -6
  49. package/dist/deploy/cloudflare/runtime.js +73 -68
  50. package/dist/deploy/cloudflare/runtime.js.map +1 -1
  51. package/dist/deploy/contract.d.ts +57 -41
  52. package/dist/deploy/contract.js.map +1 -1
  53. package/dist/deploy/filesystem.d.ts +3 -6
  54. package/dist/deploy/filesystem.js +23 -20
  55. package/dist/deploy/filesystem.js.map +1 -1
  56. package/dist/deploy/node/runtime.d.ts +5 -3
  57. package/dist/deploy/node/runtime.js +23 -9
  58. package/dist/deploy/node/runtime.js.map +1 -1
  59. package/dist/deploy/presets.d.ts +34 -30
  60. package/dist/deploy/presets.js +56 -44
  61. package/dist/deploy/presets.js.map +1 -1
  62. package/dist/deploy/public-paths.d.ts +42 -0
  63. package/dist/deploy/public-paths.js +66 -0
  64. package/dist/deploy/public-paths.js.map +1 -0
  65. package/dist/deploy/vercel/build.d.ts +0 -1
  66. package/dist/deploy/vercel/build.js +25 -16
  67. package/dist/deploy/vercel/build.js.map +1 -1
  68. package/dist/deploy/vercel/runtime.d.ts +10 -7
  69. package/dist/deploy/vercel/runtime.js +48 -11
  70. package/dist/deploy/vercel/runtime.js.map +1 -1
  71. package/dist/index.d.ts +19 -17
  72. package/dist/index.js +20 -10
  73. package/dist/index.js.map +1 -1
  74. package/dist/router.d.ts +212 -120
  75. package/dist/router.js +3 -8
  76. package/dist/router.js.map +1 -1
  77. package/dist/runtime/boundaries.d.ts +62 -48
  78. package/dist/runtime/boundaries.js +32 -34
  79. package/dist/runtime/boundaries.js.map +1 -1
  80. package/dist/runtime/client.d.ts +20 -11
  81. package/dist/runtime/client.js +20 -10
  82. package/dist/runtime/client.js.map +1 -1
  83. package/dist/runtime/context.d.ts +304 -123
  84. package/dist/runtime/context.js +377 -149
  85. package/dist/runtime/context.js.map +1 -1
  86. package/dist/runtime/control.d.ts +15 -1
  87. package/dist/runtime/control.js +24 -0
  88. package/dist/runtime/control.js.map +1 -1
  89. package/dist/runtime/dev-protocol.d.ts +4 -9
  90. package/dist/runtime/dev-protocol.js.map +1 -1
  91. package/dist/runtime/empty-server-app.d.ts +0 -1
  92. package/dist/runtime/entry.client.d.ts +4 -1
  93. package/dist/runtime/entry.client.js +455 -313
  94. package/dist/runtime/entry.client.js.map +1 -1
  95. package/dist/runtime/entry.rsc.d.ts +15 -7
  96. package/dist/runtime/entry.rsc.js +811 -252
  97. package/dist/runtime/entry.rsc.js.map +1 -1
  98. package/dist/runtime/entry.ssr.d.ts +27 -10
  99. package/dist/runtime/entry.ssr.js +30 -48
  100. package/dist/runtime/entry.ssr.js.map +1 -1
  101. package/dist/runtime/failure-document.d.ts +11 -0
  102. package/dist/runtime/failure-document.js +35 -0
  103. package/dist/runtime/failure-document.js.map +1 -0
  104. package/dist/runtime/flight-inject.d.ts +23 -0
  105. package/dist/runtime/flight-inject.js +403 -0
  106. package/dist/runtime/flight-inject.js.map +1 -0
  107. package/dist/runtime/hot-update.d.ts +44 -0
  108. package/dist/runtime/hot-update.js +44 -0
  109. package/dist/runtime/hot-update.js.map +1 -0
  110. package/dist/runtime/navigation.d.ts +46 -54
  111. package/dist/runtime/navigation.js +22 -63
  112. package/dist/runtime/navigation.js.map +1 -1
  113. package/dist/runtime/request.d.ts +42 -8
  114. package/dist/runtime/request.js +84 -7
  115. package/dist/runtime/request.js.map +1 -1
  116. package/dist/runtime/server.d.ts +20 -18
  117. package/dist/runtime/server.js +22 -17
  118. package/dist/runtime/server.js.map +1 -1
  119. package/dist/runtime/validate-entries.d.ts +77 -0
  120. package/dist/runtime/validate-entries.js +405 -0
  121. package/dist/runtime/validate-entries.js.map +1 -0
  122. package/dist/server/headers.d.ts +41 -15
  123. package/dist/server/headers.js +53 -24
  124. package/dist/server/headers.js.map +1 -1
  125. package/dist/server/load-config.d.ts +4 -5
  126. package/dist/server/load-config.js +22 -14
  127. package/dist/server/load-config.js.map +1 -1
  128. package/dist/server/load-env.d.ts +0 -1
  129. package/dist/server/prerendered.d.ts +88 -34
  130. package/dist/server/prerendered.js +184 -24
  131. package/dist/server/prerendered.js.map +1 -1
  132. package/dist/server/server-config.d.ts +35 -50
  133. package/dist/server/server-config.js +27 -74
  134. package/dist/server/server-config.js.map +1 -1
  135. package/dist/server/shutdown.d.ts +5 -4
  136. package/dist/server/shutdown.js +5 -3
  137. package/dist/server/shutdown.js.map +1 -1
  138. package/dist/server/ssg.d.ts +9 -7
  139. package/dist/server/ssg.js +209 -65
  140. package/dist/server/ssg.js.map +1 -1
  141. package/dist/server/static.d.ts +0 -1
  142. package/dist/server/static.js +7 -1
  143. package/dist/server/static.js.map +1 -1
  144. package/package.json +21 -23
  145. package/dist/builder/page-files.d.ts.map +0 -1
  146. package/dist/builder/public-env.d.ts.map +0 -1
  147. package/dist/builder/rspack-config.d.ts.map +0 -1
  148. package/dist/cli/build.d.ts.map +0 -1
  149. package/dist/cli/dev.d.ts.map +0 -1
  150. package/dist/cli/index.d.ts.map +0 -1
  151. package/dist/cli/start.d.ts.map +0 -1
  152. package/dist/config.d.ts.map +0 -1
  153. package/dist/deploy/aws-lambda/runtime.d.ts.map +0 -1
  154. package/dist/deploy/build-marker.d.ts.map +0 -1
  155. package/dist/deploy/bun/runtime.d.ts +0 -11
  156. package/dist/deploy/bun/runtime.d.ts.map +0 -1
  157. package/dist/deploy/bun/runtime.js +0 -22
  158. package/dist/deploy/bun/runtime.js.map +0 -1
  159. package/dist/deploy/cloudflare/build.d.ts.map +0 -1
  160. package/dist/deploy/cloudflare/runtime.d.ts.map +0 -1
  161. package/dist/deploy/contract.d.ts.map +0 -1
  162. package/dist/deploy/deno/runtime.d.ts +0 -11
  163. package/dist/deploy/deno/runtime.d.ts.map +0 -1
  164. package/dist/deploy/deno/runtime.js +0 -16
  165. package/dist/deploy/deno/runtime.js.map +0 -1
  166. package/dist/deploy/filesystem.d.ts.map +0 -1
  167. package/dist/deploy/listen.d.ts +0 -20
  168. package/dist/deploy/listen.d.ts.map +0 -1
  169. package/dist/deploy/listen.js +0 -24
  170. package/dist/deploy/listen.js.map +0 -1
  171. package/dist/deploy/netlify/build.d.ts +0 -8
  172. package/dist/deploy/netlify/build.d.ts.map +0 -1
  173. package/dist/deploy/netlify/build.js +0 -52
  174. package/dist/deploy/netlify/build.js.map +0 -1
  175. package/dist/deploy/netlify/runtime.d.ts +0 -13
  176. package/dist/deploy/netlify/runtime.d.ts.map +0 -1
  177. package/dist/deploy/netlify/runtime.js +0 -24
  178. package/dist/deploy/netlify/runtime.js.map +0 -1
  179. package/dist/deploy/node/runtime.d.ts.map +0 -1
  180. package/dist/deploy/presets.d.ts.map +0 -1
  181. package/dist/deploy/vercel/build.d.ts.map +0 -1
  182. package/dist/deploy/vercel/runtime.d.ts.map +0 -1
  183. package/dist/index.d.ts.map +0 -1
  184. package/dist/router.d.ts.map +0 -1
  185. package/dist/runtime/boundaries.d.ts.map +0 -1
  186. package/dist/runtime/client.d.ts.map +0 -1
  187. package/dist/runtime/context.d.ts.map +0 -1
  188. package/dist/runtime/control.d.ts.map +0 -1
  189. package/dist/runtime/dev-protocol.d.ts.map +0 -1
  190. package/dist/runtime/empty-server-app.d.ts.map +0 -1
  191. package/dist/runtime/entry.client.d.ts.map +0 -1
  192. package/dist/runtime/entry.rsc.d.ts.map +0 -1
  193. package/dist/runtime/entry.ssr.d.ts.map +0 -1
  194. package/dist/runtime/navigation.d.ts.map +0 -1
  195. package/dist/runtime/request.d.ts.map +0 -1
  196. package/dist/runtime/server.d.ts.map +0 -1
  197. package/dist/server/compress.d.ts +0 -15
  198. package/dist/server/compress.d.ts.map +0 -1
  199. package/dist/server/compress.js +0 -76
  200. package/dist/server/compress.js.map +0 -1
  201. package/dist/server/headers.d.ts.map +0 -1
  202. package/dist/server/load-config.d.ts.map +0 -1
  203. package/dist/server/load-env.d.ts.map +0 -1
  204. package/dist/server/prerendered.d.ts.map +0 -1
  205. package/dist/server/server-config.d.ts.map +0 -1
  206. package/dist/server/shutdown.d.ts.map +0 -1
  207. package/dist/server/ssg.d.ts.map +0 -1
  208. package/dist/server/static.d.ts.map +0 -1
@@ -0,0 +1,42 @@
1
+ import { type Route } from '../router.js';
2
+ /**
3
+ * The request paths a `public/` tree answers, and the collisions with the route table that only show up
4
+ * after a deploy.
5
+ *
6
+ * `DeployRuntime.mountPublicFallback` registers `public/` **after** every route, so it answers only what no
7
+ * route claimed. That is the whole story on `node` and `aws-lambda`, where the app owns the URL surface. On
8
+ * the two targets with a CDN in front, `public/` is part of the static output and the platform answers from
9
+ * it **before** the app is invoked:
10
+ *
11
+ * - **vercel** — `{ handle: 'filesystem' }` sits ahead of the catch-all in `config.json`, by construction.
12
+ * - **cloudflare** — Workers Assets is checked first, which the generated `wrangler.jsonc` says out loud.
13
+ *
14
+ * So an app with `public/about.html` and a page route at `/about.html` renders the page under `rshono dev`
15
+ * and `rshono start`, and serves the file on those two — a behaviour difference discovered by deploying. A
16
+ * `public/index.html` beside a page route at `/` is the same collision, on the one path every app has.
17
+ *
18
+ * The framework cannot reorder either platform, so this is a build-time warning: the build knows both sides
19
+ * and comparing them is a set lookup.
20
+ */
21
+ /** `.html` files are also reachable without the extension where the platform's HTML handling does that. */
22
+ export interface PublicPathOptions {
23
+ /**
24
+ * Whether `public/about.html` also answers `/about`. True on Cloudflare, whose Workers Assets defaults to
25
+ * `auto-trailing-slash` HTML handling; false on Vercel, which serves the file at its own path unless the
26
+ * project turns `cleanUrls` on. Getting this wrong in the permissive direction is a warning about a
27
+ * collision the platform does not have, which is the noise that gets a check ignored.
28
+ */
29
+ htmlExtensionless: boolean;
30
+ }
31
+ /**
32
+ * The literal route paths a `public/` file would answer instead, on a target whose platform serves the
33
+ * static output first — `[]` when there is no `public/` directory or nothing collides.
34
+ *
35
+ * Literal paths only. A `public/` file landing inside a parameterised route's pattern is a real collision
36
+ * too, but deciding it needs the router rather than a set, and the paths every app actually writes files
37
+ * beside — `/`, `/about`, `/favicon.ico` — are literal. The limit is here rather than in the message
38
+ * because a reader of the message can do nothing with it.
39
+ */
40
+ export declare function publicRouteCollisions(publicDir: string | null, routes: readonly Route[], options: PublicPathOptions): string[];
41
+ /** The warning both CDN presets print, so the two say the same thing about the same problem. */
42
+ export declare function warnAboutPublicCollisions(collisions: string[], target: string): void;
@@ -0,0 +1,66 @@
1
+ import { readdirSync } from 'node:fs';
2
+ import { join, posix } from 'node:path';
3
+ import { isPageRoute } from '../router.js';
4
+ /** Every file in a directory tree, as a `/`-separated path relative to its root. */
5
+ function filesUnder(root, prefix = '') {
6
+ const found = [];
7
+ for (const entry of readdirSync(join(root, prefix), { withFileTypes: true })) {
8
+ const rel = prefix ? posix.join(prefix, entry.name) : entry.name;
9
+ if (entry.isDirectory())
10
+ found.push(...filesUnder(root, rel));
11
+ else if (entry.isFile())
12
+ found.push(rel);
13
+ }
14
+ return found;
15
+ }
16
+ /**
17
+ * The request paths one `public/` file is served at — its own, plus the extra ones a platform's HTML
18
+ * handling adds. The same normalisation `ssgFilePath` does for a prerendered page, in the other direction:
19
+ * a check keyed on raw filenames would miss `/` for `index.html` and would be wrong about the rest.
20
+ *
21
+ * Deliberately not exhaustive. It lists what a file is *certainly* reachable at, because a false warning
22
+ * about a route that works is worse than the collision it would have caught — the same asymmetry
23
+ * `assertNothingIsShadowed` keeps.
24
+ */
25
+ function pathsFor(file, options) {
26
+ const paths = [`/${file}`];
27
+ const index = file === 'index.html' ? '' : file.endsWith('/index.html') ? file.slice(0, -'/index.html'.length) : null;
28
+ if (index !== null)
29
+ paths.push(`/${index}`, `/${index}/`);
30
+ else if (options.htmlExtensionless && file.endsWith('.html'))
31
+ paths.push(`/${file.slice(0, -'.html'.length)}`);
32
+ return [...new Set(paths)];
33
+ }
34
+ /**
35
+ * The literal route paths a `public/` file would answer instead, on a target whose platform serves the
36
+ * static output first — `[]` when there is no `public/` directory or nothing collides.
37
+ *
38
+ * Literal paths only. A `public/` file landing inside a parameterised route's pattern is a real collision
39
+ * too, but deciding it needs the router rather than a set, and the paths every app actually writes files
40
+ * beside — `/`, `/about`, `/favicon.ico` — are literal. The limit is here rather than in the message
41
+ * because a reader of the message can do nothing with it.
42
+ */
43
+ export function publicRouteCollisions(publicDir, routes, options) {
44
+ if (publicDir === null)
45
+ return [];
46
+ const claimed = new Map(routes.filter((route) => !route.path.includes(':') && !route.path.includes('*')).map((route) => [route.path, route]));
47
+ const collisions = [];
48
+ for (const file of filesUnder(publicDir)) {
49
+ for (const path of pathsFor(file, options)) {
50
+ const route = claimed.get(path);
51
+ if (route)
52
+ collisions.push(`public/${file} answers ${path}, which ${isPageRoute(route) ? 'a page' : 'an endpoint'} route claims`);
53
+ }
54
+ }
55
+ return collisions;
56
+ }
57
+ /** The warning both CDN presets print, so the two say the same thing about the same problem. */
58
+ export function warnAboutPublicCollisions(collisions, target) {
59
+ if (collisions.length === 0)
60
+ return;
61
+ console.warn(` ⚠ ${collisions.length} public/ file(s) shadow a route on ${target}, where the CDN answers before the app is invoked:`);
62
+ for (const line of collisions)
63
+ console.warn(` ${line}`);
64
+ console.warn(` Under \`rshono dev\` and \`rshono start\` the route wins instead, so this only appears once deployed.`);
65
+ }
66
+ //# sourceMappingURL=public-paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-paths.js","sourceRoot":"","sources":["../../src/deploy/public-paths.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync } from 'node:fs';\nimport { join, posix } from 'node:path';\nimport { isPageRoute, type Route } from '../router.js';\n\n/**\n * The request paths a `public/` tree answers, and the collisions with the route table that only show up\n * after a deploy.\n *\n * `DeployRuntime.mountPublicFallback` registers `public/` **after** every route, so it answers only what no\n * route claimed. That is the whole story on `node` and `aws-lambda`, where the app owns the URL surface. On\n * the two targets with a CDN in front, `public/` is part of the static output and the platform answers from\n * it **before** the app is invoked:\n *\n * - **vercel** — `{ handle: 'filesystem' }` sits ahead of the catch-all in `config.json`, by construction.\n * - **cloudflare** — Workers Assets is checked first, which the generated `wrangler.jsonc` says out loud.\n *\n * So an app with `public/about.html` and a page route at `/about.html` renders the page under `rshono dev`\n * and `rshono start`, and serves the file on those two — a behaviour difference discovered by deploying. A\n * `public/index.html` beside a page route at `/` is the same collision, on the one path every app has.\n *\n * The framework cannot reorder either platform, so this is a build-time warning: the build knows both sides\n * and comparing them is a set lookup.\n */\n\n/** `.html` files are also reachable without the extension where the platform's HTML handling does that. */\nexport interface PublicPathOptions {\n /**\n * Whether `public/about.html` also answers `/about`. True on Cloudflare, whose Workers Assets defaults to\n * `auto-trailing-slash` HTML handling; false on Vercel, which serves the file at its own path unless the\n * project turns `cleanUrls` on. Getting this wrong in the permissive direction is a warning about a\n * collision the platform does not have, which is the noise that gets a check ignored.\n */\n htmlExtensionless: boolean;\n}\n\n/** Every file in a directory tree, as a `/`-separated path relative to its root. */\nfunction filesUnder(root: string, prefix = ''): string[] {\n const found: string[] = [];\n for (const entry of readdirSync(join(root, prefix), { withFileTypes: true })) {\n const rel = prefix ? posix.join(prefix, entry.name) : entry.name;\n if (entry.isDirectory()) found.push(...filesUnder(root, rel));\n else if (entry.isFile()) found.push(rel);\n }\n return found;\n}\n\n/**\n * The request paths one `public/` file is served at — its own, plus the extra ones a platform's HTML\n * handling adds. The same normalisation `ssgFilePath` does for a prerendered page, in the other direction:\n * a check keyed on raw filenames would miss `/` for `index.html` and would be wrong about the rest.\n *\n * Deliberately not exhaustive. It lists what a file is *certainly* reachable at, because a false warning\n * about a route that works is worse than the collision it would have caught — the same asymmetry\n * `assertNothingIsShadowed` keeps.\n */\nfunction pathsFor(file: string, options: PublicPathOptions): string[] {\n const paths = [`/${file}`];\n const index = file === 'index.html' ? '' : file.endsWith('/index.html') ? file.slice(0, -'/index.html'.length) : null;\n if (index !== null) paths.push(`/${index}`, `/${index}/`);\n else if (options.htmlExtensionless && file.endsWith('.html')) paths.push(`/${file.slice(0, -'.html'.length)}`);\n return [...new Set(paths)];\n}\n\n/**\n * The literal route paths a `public/` file would answer instead, on a target whose platform serves the\n * static output first — `[]` when there is no `public/` directory or nothing collides.\n *\n * Literal paths only. A `public/` file landing inside a parameterised route's pattern is a real collision\n * too, but deciding it needs the router rather than a set, and the paths every app actually writes files\n * beside — `/`, `/about`, `/favicon.ico` — are literal. The limit is here rather than in the message\n * because a reader of the message can do nothing with it.\n */\nexport function publicRouteCollisions(publicDir: string | null, routes: readonly Route[], options: PublicPathOptions): string[] {\n if (publicDir === null) return [];\n const claimed = new Map(routes.filter((route) => !route.path.includes(':') && !route.path.includes('*')).map((route) => [route.path, route]));\n const collisions: string[] = [];\n for (const file of filesUnder(publicDir)) {\n for (const path of pathsFor(file, options)) {\n const route = claimed.get(path);\n if (route) collisions.push(`public/${file} answers ${path}, which ${isPageRoute(route) ? 'a page' : 'an endpoint'} route claims`);\n }\n }\n return collisions;\n}\n\n/** The warning both CDN presets print, so the two say the same thing about the same problem. */\nexport function warnAboutPublicCollisions(collisions: string[], target: string): void {\n if (collisions.length === 0) return;\n console.warn(` ⚠ ${collisions.length} public/ file(s) shadow a route on ${target}, where the CDN answers before the app is invoked:`);\n for (const line of collisions) console.warn(` ${line}`);\n console.warn(` Under \\`rshono dev\\` and \\`rshono start\\` the route wins instead, so this only appears once deployed.`);\n}\n"]}
@@ -1,3 +1,2 @@
1
1
  import type { DeployBuildContext } from '../presets.js';
2
2
  export declare function finalizeVercelBuild(ctx: DeployBuildContext): Promise<void>;
3
- //# sourceMappingURL=build.d.ts.map
@@ -1,24 +1,22 @@
1
1
  import { cpSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
2
2
  import { rm } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
+ import { publicRouteCollisions, warnAboutPublicCollisions } from '../public-paths.js';
4
5
  /**
5
- * The Build Output API v3 layout, which is what `vercel deploy --prebuilt` uploads verbatim. Producing
6
- * it directly means Vercel runs no build of its own — everything it needs already exists.
6
+ * The Build Output API v3 layout, which `vercel deploy --prebuilt` uploads verbatim — producing it directly
7
+ * means Vercel runs no build of its own.
7
8
  */
8
9
  const OUTPUT_DIR = join('.vercel', 'output');
9
10
  const FUNCTION_DIR = join('functions', 'index.func');
10
11
  /**
11
- * The function's own view of the build.
12
- *
13
- * `dist/server/main.mjs` is kept at that exact path inside the function because the runtime derives the
14
- * project root from where the bundle sits (see `deploy/filesystem.ts`) — so `dist/ssg` and `dist/public`
15
- * land where it already looks for them, and no runtime code needs to know it is on Vercel.
12
+ * The bundle keeps this exact path inside the function because the runtime derives the project root from where
13
+ * it sits (see `deploy/filesystem.ts`), so `dist/ssg` and `dist/public` land where it already looks — and no
14
+ * runtime code needs to know it is on Vercel.
16
15
  */
17
16
  const HANDLER = 'dist/server/main.mjs';
18
17
  /**
19
- * Routes, in the order Vercel evaluates them: hashed assets get the immutable header the CDN cannot
20
- * infer, then anything present in the static output is served from it, and whatever is left is the
21
- * app's to render.
18
+ * Routes, in the order Vercel evaluates them: hashed assets get the immutable header the CDN cannot infer,
19
+ * then anything in the static output is served from it, and whatever is left is the app's to render.
22
20
  */
23
21
  const ROUTES = [
24
22
  { src: '^/_static/(.*)$', headers: { 'cache-control': 'public, max-age=31536000, immutable' }, continue: true },
@@ -29,7 +27,7 @@ export async function finalizeVercelBuild(ctx) {
29
27
  const outputDir = join(ctx.rootDir, OUTPUT_DIR);
30
28
  const staticOut = join(outputDir, 'static');
31
29
  const functionDir = join(outputDir, FUNCTION_DIR);
32
- // Rebuilt from scratch, so a deleted page or asset cannot survive in the uploaded output.
30
+ // From scratch, so a deleted page or asset cannot survive in the uploaded output.
33
31
  await rm(outputDir, { recursive: true, force: true });
34
32
  mkdirSync(staticOut, { recursive: true });
35
33
  mkdirSync(functionDir, { recursive: true });
@@ -37,17 +35,28 @@ export async function finalizeVercelBuild(ctx) {
37
35
  cpSync(ctx.staticDir, join(staticOut, '_static'), { recursive: true });
38
36
  if (ctx.publicDir)
39
37
  cpSync(ctx.publicDir, staticOut, { recursive: true });
40
- // Shipped inside the function: the bundle, plus the two things it reads from disk at request time.
38
+ // `{ handle: 'filesystem' }` is ahead of the function by construction, so a `public/` file on a route's
39
+ // path answers instead of the route here — and only here, which is what makes it worth saying at build
40
+ // time. `htmlExtensionless: false`: Vercel serves `about.html` at `/about.html` and adds `/about` only
41
+ // with `cleanUrls`, which is the project's setting and not something this build can read.
42
+ warnAboutPublicCollisions(publicRouteCollisions(ctx.publicDir, ctx.routes, { htmlExtensionless: false }), 'vercel');
43
+ // Shipped inside the function: the bundle, and the one thing it reads from disk at request time.
44
+ //
45
+ // `public/` is deliberately *not* among them, though it is on the filesystem targets. It went into the
46
+ // static output above, and `{ handle: 'filesystem' }` sits ahead of the catch-all route, so the platform
47
+ // answers those paths before the function is invoked — a copy here is bytes uploaded and unpacked on every
48
+ // cold start that nothing can ever read. `vercel/runtime.ts` turns the matching mount off to say so.
41
49
  cpSync(join(ctx.distDir, 'server'), join(functionDir, 'dist', 'server'), { recursive: true });
42
50
  if (existsSync(ctx.ssgDir))
43
51
  cpSync(ctx.ssgDir, join(functionDir, 'dist', 'ssg'), { recursive: true });
44
- if (ctx.publicDir)
45
- cpSync(ctx.publicDir, join(functionDir, 'dist', 'public'), { recursive: true });
46
52
  writeFileSync(join(functionDir, '.vc-config.json'), `${JSON.stringify({
47
- runtime: 'nodejs22.x',
53
+ // The Node the build ran on, so the function runs the runtime the app was tested against — and so
54
+ // this does not become a hard-coded version the platform retires on a date the framework does not
55
+ // control. A major Vercel does not offer is an explicit error from the deploy rather than a mismatch.
56
+ runtime: `nodejs${process.versions.node.split('.')[0]}.x`,
48
57
  handler: HANDLER,
49
58
  launcherType: 'Nodejs',
50
- // Without this the platform buffers the whole response, which would undo streamed SSR.
59
+ // Without this the platform buffers the whole response, undoing streamed SSR.
51
60
  supportsResponseStreaming: true,
52
61
  }, null, 2)}\n`);
53
62
  writeFileSync(join(outputDir, 'config.json'), `${JSON.stringify({ version: 3, routes: ROUTES }, null, 2)}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/deploy/vercel/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { cpSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DeployBuildContext } from '../presets.js';\n\n/**\n * The Build Output API v3 layout, which is what `vercel deploy --prebuilt` uploads verbatim. Producing\n * it directly means Vercel runs no build of its own — everything it needs already exists.\n */\nconst OUTPUT_DIR = join('.vercel', 'output');\nconst FUNCTION_DIR = join('functions', 'index.func');\n\n/**\n * The function's own view of the build.\n *\n * `dist/server/main.mjs` is kept at that exact path inside the function because the runtime derives the\n * project root from where the bundle sits (see `deploy/filesystem.ts`) so `dist/ssg` and `dist/public`\n * land where it already looks for them, and no runtime code needs to know it is on Vercel.\n */\nconst HANDLER = 'dist/server/main.mjs';\n\n/**\n * Routes, in the order Vercel evaluates them: hashed assets get the immutable header the CDN cannot\n * infer, then anything present in the static output is served from it, and whatever is left is the\n * app's to render.\n */\nconst ROUTES = [\n { src: '^/_static/(.*)$', headers: { 'cache-control': 'public, max-age=31536000, immutable' }, continue: true },\n { handle: 'filesystem' },\n { src: '/(.*)', dest: '/index' },\n];\n\nexport async function finalizeVercelBuild(ctx: DeployBuildContext): Promise<void> {\n const outputDir = join(ctx.rootDir, OUTPUT_DIR);\n const staticOut = join(outputDir, 'static');\n const functionDir = join(outputDir, FUNCTION_DIR);\n\n // Rebuilt from scratch, so a deleted page or asset cannot survive in the uploaded output.\n await rm(outputDir, { recursive: true, force: true });\n mkdirSync(staticOut, { recursive: true });\n mkdirSync(functionDir, { recursive: true });\n\n // Served by the CDN: the hashed bundle under its public path, and `public/` at the web root.\n cpSync(ctx.staticDir, join(staticOut, '_static'), { recursive: true });\n if (ctx.publicDir) cpSync(ctx.publicDir, staticOut, { recursive: true });\n\n // Shipped inside the function: the bundle, plus the two things it reads from disk at request time.\n cpSync(join(ctx.distDir, 'server'), join(functionDir, 'dist', 'server'), { recursive: true });\n if (existsSync(ctx.ssgDir)) cpSync(ctx.ssgDir, join(functionDir, 'dist', 'ssg'), { recursive: true });\n if (ctx.publicDir) cpSync(ctx.publicDir, join(functionDir, 'dist', 'public'), { recursive: true });\n\n writeFileSync(\n join(functionDir, '.vc-config.json'),\n `${JSON.stringify(\n {\n runtime: 'nodejs22.x',\n handler: HANDLER,\n launcherType: 'Nodejs',\n // Without this the platform buffers the whole response, which would undo streamed SSR.\n supportsResponseStreaming: true,\n },\n null,\n 2,\n )}\\n`,\n );\n\n writeFileSync(join(outputDir, 'config.json'), `${JSON.stringify({ version: 3, routes: ROUTES }, null, 2)}\\n`);\n\n console.log(` • assembled ${OUTPUT_DIR} (Build Output API v3)`);\n}\n"]}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/deploy/vercel/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { cpSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { DeployBuildContext } from '../presets.js';\nimport { publicRouteCollisions, warnAboutPublicCollisions } from '../public-paths.js';\n\n/**\n * The Build Output API v3 layout, which `vercel deploy --prebuilt` uploads verbatim producing it directly\n * means Vercel runs no build of its own.\n */\nconst OUTPUT_DIR = join('.vercel', 'output');\nconst FUNCTION_DIR = join('functions', 'index.func');\n\n/**\n * The bundle keeps this exact path inside the function because the runtime derives the project root from where\n * it sits (see `deploy/filesystem.ts`), so `dist/ssg` and `dist/public` land where it already looks and no\n * runtime code needs to know it is on Vercel.\n */\nconst HANDLER = 'dist/server/main.mjs';\n\n/**\n * Routes, in the order Vercel evaluates them: hashed assets get the immutable header the CDN cannot infer,\n * then anything in the static output is served from it, and whatever is left is the app's to render.\n */\nconst ROUTES = [\n { src: '^/_static/(.*)$', headers: { 'cache-control': 'public, max-age=31536000, immutable' }, continue: true },\n { handle: 'filesystem' },\n { src: '/(.*)', dest: '/index' },\n];\n\nexport async function finalizeVercelBuild(ctx: DeployBuildContext): Promise<void> {\n const outputDir = join(ctx.rootDir, OUTPUT_DIR);\n const staticOut = join(outputDir, 'static');\n const functionDir = join(outputDir, FUNCTION_DIR);\n\n // From scratch, so a deleted page or asset cannot survive in the uploaded output.\n await rm(outputDir, { recursive: true, force: true });\n mkdirSync(staticOut, { recursive: true });\n mkdirSync(functionDir, { recursive: true });\n\n // Served by the CDN: the hashed bundle under its public path, and `public/` at the web root.\n cpSync(ctx.staticDir, join(staticOut, '_static'), { recursive: true });\n if (ctx.publicDir) cpSync(ctx.publicDir, staticOut, { recursive: true });\n\n // `{ handle: 'filesystem' }` is ahead of the function by construction, so a `public/` file on a route's\n // path answers instead of the route here — and only here, which is what makes it worth saying at build\n // time. `htmlExtensionless: false`: Vercel serves `about.html` at `/about.html` and adds `/about` only\n // with `cleanUrls`, which is the project's setting and not something this build can read.\n warnAboutPublicCollisions(publicRouteCollisions(ctx.publicDir, ctx.routes, { htmlExtensionless: false }), 'vercel');\n\n // Shipped inside the function: the bundle, and the one thing it reads from disk at request time.\n //\n // `public/` is deliberately *not* among them, though it is on the filesystem targets. It went into the\n // static output above, and `{ handle: 'filesystem' }` sits ahead of the catch-all route, so the platform\n // answers those paths before the function is invoked — a copy here is bytes uploaded and unpacked on every\n // cold start that nothing can ever read. `vercel/runtime.ts` turns the matching mount off to say so.\n cpSync(join(ctx.distDir, 'server'), join(functionDir, 'dist', 'server'), { recursive: true });\n if (existsSync(ctx.ssgDir)) cpSync(ctx.ssgDir, join(functionDir, 'dist', 'ssg'), { recursive: true });\n\n writeFileSync(\n join(functionDir, '.vc-config.json'),\n `${JSON.stringify(\n {\n // The Node the build ran on, so the function runs the runtime the app was tested against — and so\n // this does not become a hard-coded version the platform retires on a date the framework does not\n // control. A major Vercel does not offer is an explicit error from the deploy rather than a mismatch.\n runtime: `nodejs${process.versions.node.split('.')[0]}.x`,\n handler: HANDLER,\n launcherType: 'Nodejs',\n // Without this the platform buffers the whole response, undoing streamed SSR.\n supportsResponseStreaming: true,\n },\n null,\n 2,\n )}\\n`,\n );\n\n writeFileSync(join(outputDir, 'config.json'), `${JSON.stringify({ version: 3, routes: ROUTES }, null, 2)}\\n`);\n\n console.log(` • assembled ${OUTPUT_DIR} (Build Output API v3)`);\n}\n"]}
@@ -2,13 +2,16 @@ import type { DeployRuntime } from '../contract.js';
2
2
  /**
3
3
  * Vercel, as a single Node function fed by the platform's own router.
4
4
  *
5
- * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler
6
- * ahead of the function so the CDN answers them and the function is never invoked for an asset,
7
- * which is why mounting them here would only be dead weight.
5
+ * The function is invoked the way `launcherType: 'Nodejs'` invokes one with `(IncomingMessage,
6
+ * ServerResponse)`, not a web `Request`. That is the whole of the Build Output API's Node contract; the
7
+ * `Request`/`Response` handler shape the platform documents elsewhere belongs to the `@vercel/node` builder,
8
+ * which compiles and wraps a source file, and a `--prebuilt` upload never runs it. So the handoff converts,
9
+ * and `hono/vercel`'s `handle` — a pass-through that forwards its first argument straight to `app.fetch` —
10
+ * cannot be what does it.
8
11
  *
9
- * Prerendered pages are *not* static output: one URL answers with a document or a flight payload
10
- * depending on `Accept`, and a path-keyed CDN cannot choose. They ship inside the function instead and
11
- * are read from its read-only disk, exactly as on a server.
12
+ * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler ahead of the
13
+ * function, so mounting them here would be dead weight. Prerendered pages are *not* static output — one URL
14
+ * answers with a document or a flight payload on the `RSC` request header, and a path-keyed CDN cannot choose — so
15
+ * they ship inside the function and are read from its read-only disk, exactly as on a server.
12
16
  */
13
17
  export declare const runtime: DeployRuntime;
14
- //# sourceMappingURL=runtime.d.ts.map
@@ -1,26 +1,63 @@
1
- import { handle } from 'hono/vercel';
1
+ import { getRequestListener } from '@hono/node-server';
2
2
  import { fileSystemRuntime } from '../filesystem.js';
3
+ /**
4
+ * The scheme the browser used, which the socket cannot answer for: Vercel terminates TLS at the edge and
5
+ * reaches the function over plain HTTP, so an `https://` request arrives on an unencrypted socket and every
6
+ * absolute URL the app derived from it would carry the wrong scheme — a redirect back to `http://`, an
7
+ * origin check comparing against one.
8
+ *
9
+ * Read without `trustProxy`, unlike `publicUrl`, because on this target the header is not
10
+ * client-supplied: the function is reachable only through Vercel's edge, which sets it on every request. The
11
+ * config field stays what it is — the answer for a proxy *you* put in front, which the framework cannot vouch
12
+ * for. Falls back to `https`, the only scheme a deployment is served on.
13
+ */
14
+ function browserScheme(incoming) {
15
+ const header = incoming.headers['x-forwarded-proto'];
16
+ const value = (Array.isArray(header) ? header[0] : header)?.split(',')[0]?.trim();
17
+ return value === 'http' ? 'http' : 'https';
18
+ }
3
19
  /**
4
20
  * Vercel, as a single Node function fed by the platform's own router.
5
21
  *
6
- * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler
7
- * ahead of the function so the CDN answers them and the function is never invoked for an asset,
8
- * which is why mounting them here would only be dead weight.
22
+ * The function is invoked the way `launcherType: 'Nodejs'` invokes one with `(IncomingMessage,
23
+ * ServerResponse)`, not a web `Request`. That is the whole of the Build Output API's Node contract; the
24
+ * `Request`/`Response` handler shape the platform documents elsewhere belongs to the `@vercel/node` builder,
25
+ * which compiles and wraps a source file, and a `--prebuilt` upload never runs it. So the handoff converts,
26
+ * and `hono/vercel`'s `handle` — a pass-through that forwards its first argument straight to `app.fetch` —
27
+ * cannot be what does it.
9
28
  *
10
- * Prerendered pages are *not* static output: one URL answers with a document or a flight payload
11
- * depending on `Accept`, and a path-keyed CDN cannot choose. They ship inside the function instead and
12
- * are read from its read-only disk, exactly as on a server.
29
+ * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler ahead of the
30
+ * function, so mounting them here would be dead weight. Prerendered pages are *not* static output — one URL
31
+ * answers with a document or a flight payload on the `RSC` request header, and a path-keyed CDN cannot choose — so
32
+ * they ship inside the function and are read from its read-only disk, exactly as on a server.
13
33
  */
14
34
  export const runtime = {
15
35
  ...fileSystemRuntime,
16
36
  mountStaticAssets() {
17
37
  // Served from `.vercel/output/static` before the function runs.
18
38
  },
39
+ mountPublicFallback() {
40
+ // As above: `public/` is in the static output and `{ handle: 'filesystem' }` is matched ahead of this
41
+ // function, so nothing here could ever answer for one of those paths. Stated as an override rather than
42
+ // left to fall out of `dist/public` not being uploaded, because that would make the behaviour incidental
43
+ // to a `cpSync` in `build.ts` instead of a decision.
44
+ //
45
+ // The one thing this hands to the platform: resolving a directory to its `index.html`. Vercel's static
46
+ // handler does that; `serveStatic`, which the filesystem targets use, is no longer in the path.
47
+ },
19
48
  serveApp(app) {
20
- return handle(app);
49
+ // The same conversion `rshono start` runs on, so a request is built here exactly as it is on the `node`
50
+ // target — including a streamed response body, which `supportsResponseStreaming` in `.vc-config.json`
51
+ // then keeps unbuffered on the way out.
52
+ const listener = getRequestListener(app.fetch);
53
+ return (incoming, outgoing) => {
54
+ const host = incoming.headers.host;
55
+ // Left alone when there is no `Host`, so the listener answers with its own 400 rather than this
56
+ // building `https://undefined/…` and the app rejecting a URL it should never have been handed.
57
+ if (host)
58
+ incoming.url = `${browserScheme(incoming)}://${host}${incoming.url ?? '/'}`;
59
+ return listener(incoming, outgoing);
60
+ };
21
61
  },
22
- // Vercel compresses at the edge. Its Node runtime does support streaming, so the framework's own
23
- // streamed SSR still reaches the browser progressively.
24
- compress: null,
25
62
  };
26
63
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,GAAG,iBAAiB;IAEpB,iBAAiB;QACf,gEAAgE;IAClE,CAAC;IAED,QAAQ,CAAC,GAAS;QAChB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,iGAAiG;IACjG,wDAAwD;IACxD,QAAQ,EAAE,IAAI;CACf,CAAC","sourcesContent":["import type { Hono } from 'hono';\nimport { handle } from 'hono/vercel';\nimport type { DeployRuntime } from '../contract.js';\nimport { fileSystemRuntime } from '../filesystem.js';\n\n/**\n * Vercel, as a single Node function fed by the platform's own router.\n *\n * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler\n * ahead of the function so the CDN answers them and the function is never invoked for an asset,\n * which is why mounting them here would only be dead weight.\n *\n * Prerendered pages are *not* static output: one URL answers with a document or a flight payload\n * depending on `Accept`, and a path-keyed CDN cannot choose. They ship inside the function instead and\n * are read from its read-only disk, exactly as on a server.\n */\nexport const runtime: DeployRuntime = {\n ...fileSystemRuntime,\n\n mountStaticAssets(): void {\n // Served from `.vercel/output/static` before the function runs.\n },\n\n serveApp(app: Hono): unknown {\n return handle(app);\n },\n\n // Vercel compresses at the edge. Its Node runtime does support streaming, so the framework's own\n // streamed SSR still reaches the browser progressively.\n compress: null,\n};\n"]}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAIvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,SAAS,aAAa,CAAC,QAAyB;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAClF,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,GAAG,iBAAiB;IAEpB,iBAAiB;QACf,gEAAgE;IAClE,CAAC;IAED,mBAAmB;QACjB,sGAAsG;QACtG,wGAAwG;QACxG,yGAAyG;QACzG,qDAAqD;QACrD,EAAE;QACF,uGAAuG;QACvG,gGAAgG;IAClG,CAAC;IAED,QAAQ,CAAC,GAAS;QAChB,wGAAwG;QACxG,sGAAsG;QACtG,wCAAwC;QACxC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE/C,OAAO,CAAC,QAAyB,EAAE,QAAwB,EAAiB,EAAE;YAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YACnC,gGAAgG;YAChG,+FAA+F;YAC/F,IAAI,IAAI;gBAAE,QAAQ,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC;YACtF,OAAO,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { getRequestListener } from '@hono/node-server';\nimport type { Hono } from 'hono';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { DeployRuntime } from '../contract.js';\nimport { fileSystemRuntime } from '../filesystem.js';\n\n/**\n * The scheme the browser used, which the socket cannot answer for: Vercel terminates TLS at the edge and\n * reaches the function over plain HTTP, so an `https://` request arrives on an unencrypted socket and every\n * absolute URL the app derived from it would carry the wrong scheme — a redirect back to `http://`, an\n * origin check comparing against one.\n *\n * Read without `trustProxy`, unlike `publicUrl`, because on this target the header is not\n * client-supplied: the function is reachable only through Vercel's edge, which sets it on every request. The\n * config field stays what it is — the answer for a proxy *you* put in front, which the framework cannot vouch\n * for. Falls back to `https`, the only scheme a deployment is served on.\n */\nfunction browserScheme(incoming: IncomingMessage): string {\n const header = incoming.headers['x-forwarded-proto'];\n const value = (Array.isArray(header) ? header[0] : header)?.split(',')[0]?.trim();\n return value === 'http' ? 'http' : 'https';\n}\n\n/**\n * Vercel, as a single Node function fed by the platform's own router.\n *\n * The function is invoked the way `launcherType: 'Nodejs'` invokes one — with `(IncomingMessage,\n * ServerResponse)`, not a web `Request`. That is the whole of the Build Output API's Node contract; the\n * `Request`/`Response` handler shape the platform documents elsewhere belongs to the `@vercel/node` builder,\n * which compiles and wraps a source file, and a `--prebuilt` upload never runs it. So the handoff converts,\n * and `hono/vercel`'s `handle` a pass-through that forwards its first argument straight to `app.fetch` —\n * cannot be what does it.\n *\n * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler ahead of the\n * function, so mounting them here would be dead weight. Prerendered pages are *not* static output one URL\n * answers with a document or a flight payload on the `RSC` request header, and a path-keyed CDN cannot choose so\n * they ship inside the function and are read from its read-only disk, exactly as on a server.\n */\nexport const runtime: DeployRuntime = {\n ...fileSystemRuntime,\n\n mountStaticAssets(): void {\n // Served from `.vercel/output/static` before the function runs.\n },\n\n mountPublicFallback(): void {\n // As above: `public/` is in the static output and `{ handle: 'filesystem' }` is matched ahead of this\n // function, so nothing here could ever answer for one of those paths. Stated as an override rather than\n // left to fall out of `dist/public` not being uploaded, because that would make the behaviour incidental\n // to a `cpSync` in `build.ts` instead of a decision.\n //\n // The one thing this hands to the platform: resolving a directory to its `index.html`. Vercel's static\n // handler does that; `serveStatic`, which the filesystem targets use, is no longer in the path.\n },\n\n serveApp(app: Hono): unknown {\n // The same conversion `rshono start` runs on, so a request is built here exactly as it is on the `node`\n // target — including a streamed response body, which `supportsResponseStreaming` in `.vc-config.json`\n // then keeps unbuffered on the way out.\n const listener = getRequestListener(app.fetch);\n\n return (incoming: IncomingMessage, outgoing: ServerResponse): Promise<void> => {\n const host = incoming.headers.host;\n // Left alone when there is no `Host`, so the listener answers with its own 400 rather than this\n // building `https://undefined/…` and the app rejecting a URL it should never have been handed.\n if (host) incoming.url = `${browserScheme(incoming)}://${host}${incoming.url ?? '/'}`;\n return listener(incoming, outgoing);\n };\n },\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -1,23 +1,25 @@
1
1
  /**
2
- * `@rshono/core` — the build-time surface: route and config declaration plus the types
3
- * your pages and endpoints are written against. Everything here is safe to
4
- * import from server code; none of it pulls in runtime machinery.
2
+ * `@rshono/core` — the build-time surface: route and config declaration, plus the types
3
+ * your pages and endpoints are written against. Nothing here pulls in runtime machinery.
5
4
  *
6
- * The two companion entry points are runtime-only:
7
- * - `@rshono/core/server` — {@link https://hono.dev | Hono} request context inside
8
- * server components and actions (`getContext`, `redirect`, `notFound`), plus
9
- * `onServerError` for reporting the errors the framework catches.
10
- * - `@rshono/core/client` hooks and components for `'use client'` modules
11
- * (`useNavigation`, `Boundary`, `ErrorBoundary`, `NavigationProgress`).
5
+ * Two companion entry points are runtime-only:
6
+ * - `@rshono/core/server` — request context, `redirect`, `notFound`, `onServerError`, `publicUrl`.
7
+ * - `@rshono/core/client` `useNavigation`, `AsyncBoundary`, `CatchBoundary`.
8
+ *
9
+ * ESM only: the `exports` map declares `types` and `import` conditions and no `require` one.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // src/routes.ts
14
+ * import { defineRoutes } from '@rshono/core';
15
+ *
16
+ * export const routes = defineRoutes([{ path: '/', component: () => import('./components/home') }]);
17
+ * ```
18
+ *
19
+ * @see {@link https://www.rshono.com/docs/api | Docs — API reference}
12
20
  *
13
21
  * @packageDocumentation
14
22
  */
15
- export { defineRoutes, isPageRoute, type EndpointRoute, type EndpointServerModule, type ErrorInfo, type ErrorPageProps, type FallbackPage, type HTTPMethod, type PageComponent, type PageProps, type PageRoute, type PathParams, type Route, type RouteConfig, } from './router.js';
16
- export { defineConfig, type RSHonoConfig, type RspackHookContext } from './config.js';
23
+ export { defineRoutes, type EndpointRoute, type EndpointServerModule, type ErrorPageInfo, type ErrorPageProps, type FallbackPage, type HTTPMethod, type PageComponent, type PageProps, type PageRoute, type PathParams, type Route, type RouteConfig, } from './router.js';
24
+ export { defineConfig, type RshonoConfig, type RspackHookContext } from './config.js';
17
25
  export type { DeployTarget } from './deploy/contract.js';
18
- /**
19
- * Re-exported from Hono for convenience, so an endpoint module can type its
20
- * `handler` without depending on `hono` directly.
21
- */
22
- export type { Context, Handler } from 'hono';
23
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,17 +1,27 @@
1
1
  /**
2
- * `@rshono/core` — the build-time surface: route and config declaration plus the types
3
- * your pages and endpoints are written against. Everything here is safe to
4
- * import from server code; none of it pulls in runtime machinery.
2
+ * `@rshono/core` — the build-time surface: route and config declaration, plus the types
3
+ * your pages and endpoints are written against. Nothing here pulls in runtime machinery.
5
4
  *
6
- * The two companion entry points are runtime-only:
7
- * - `@rshono/core/server` — {@link https://hono.dev | Hono} request context inside
8
- * server components and actions (`getContext`, `redirect`, `notFound`), plus
9
- * `onServerError` for reporting the errors the framework catches.
10
- * - `@rshono/core/client` hooks and components for `'use client'` modules
11
- * (`useNavigation`, `Boundary`, `ErrorBoundary`, `NavigationProgress`).
5
+ * Two companion entry points are runtime-only:
6
+ * - `@rshono/core/server` — request context, `redirect`, `notFound`, `onServerError`, `publicUrl`.
7
+ * - `@rshono/core/client` `useNavigation`, `AsyncBoundary`, `CatchBoundary`.
8
+ *
9
+ * ESM only: the `exports` map declares `types` and `import` conditions and no `require` one.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // src/routes.ts
14
+ * import { defineRoutes } from '@rshono/core';
15
+ *
16
+ * export const routes = defineRoutes([{ path: '/', component: () => import('./components/home') }]);
17
+ * ```
18
+ *
19
+ * @see {@link https://www.rshono.com/docs/api | Docs — API reference}
12
20
  *
13
21
  * @packageDocumentation
14
22
  */
15
- export { defineRoutes, isPageRoute, } from './router.js';
23
+ export { defineRoutes, } from './router.js';
16
24
  export { defineConfig } from './config.js';
25
+ // Hono's `Context` and `Handler` are deliberately not re-exported — `hono` is a peer dependency, so
26
+ // endpoints import them from there rather than from two spellings of the same type.
17
27
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,YAAY,EACZ,WAAW,GAaZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAA6C,MAAM,aAAa,CAAC","sourcesContent":["/**\n * `@rshono/core` — the build-time surface: route and config declaration plus the types\n * your pages and endpoints are written against. Everything here is safe to\n * import from server code; none of it pulls in runtime machinery.\n *\n * The two companion entry points are runtime-only:\n * - `@rshono/core/server` — {@link https://hono.dev | Hono} request context inside\n * server components and actions (`getContext`, `redirect`, `notFound`), plus\n * `onServerError` for reporting the errors the framework catches.\n * - `@rshono/core/client` hooks and components for `'use client'` modules\n * (`useNavigation`, `Boundary`, `ErrorBoundary`, `NavigationProgress`).\n *\n * @packageDocumentation\n */\n\nexport {\n defineRoutes,\n isPageRoute,\n type EndpointRoute,\n type EndpointServerModule,\n type ErrorInfo,\n type ErrorPageProps,\n type FallbackPage,\n type HTTPMethod,\n type PageComponent,\n type PageProps,\n type PageRoute,\n type PathParams,\n type Route,\n type RouteConfig,\n} from './router.js';\n\nexport { defineConfig, type RSHonoConfig, type RspackHookContext } from './config.js';\n\nexport type { DeployTarget } from './deploy/contract.js';\n\n/**\n * Re-exported from Hono for convenience, so an endpoint module can type its\n * `handler` without depending on `hono` directly.\n */\nexport type { Context, Handler } from 'hono';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACL,YAAY,GAab,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAA6C,MAAM,aAAa,CAAC;AAItF,oGAAoG;AACpG,oFAAoF","sourcesContent":["/**\n * `@rshono/core` — the build-time surface: route and config declaration, plus the types\n * your pages and endpoints are written against. Nothing here pulls in runtime machinery.\n *\n * Two companion entry points are runtime-only:\n * - `@rshono/core/server` — request context, `redirect`, `notFound`, `onServerError`, `publicUrl`.\n * - `@rshono/core/client` `useNavigation`, `AsyncBoundary`, `CatchBoundary`.\n *\n * ESM only: the `exports` map declares `types` and `import` conditions and no `require` one.\n *\n * @example\n * ```ts\n * // src/routes.ts\n * import { defineRoutes } from '@rshono/core';\n *\n * export const routes = defineRoutes([{ path: '/', component: () => import('./components/home') }]);\n * ```\n *\n * @see {@link https://www.rshono.com/docs/api | Docs — API reference}\n *\n * @packageDocumentation\n */\n\nexport {\n defineRoutes,\n type EndpointRoute,\n type EndpointServerModule,\n type ErrorPageInfo,\n type ErrorPageProps,\n type FallbackPage,\n type HTTPMethod,\n type PageComponent,\n type PageProps,\n type PageRoute,\n type PathParams,\n type Route,\n type RouteConfig,\n} from './router.js';\n\nexport { defineConfig, type RshonoConfig, type RspackHookContext } from './config.js';\n\nexport type { DeployTarget } from './deploy/contract.js';\n\n// Hono's `Context` and `Handler` are deliberately not re-exported `hono` is a peer dependency, so\n// endpoints import them from there rather than from two spellings of the same type.\n"]}