@rshono/core 1.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +273 -0
  2. package/bin/rshono.mjs +15 -0
  3. package/dist/builder/env-shadow-loader.cjs +26 -0
  4. package/dist/builder/page-entry-loader.cjs +7 -0
  5. package/dist/builder/page-files.d.ts +2 -0
  6. package/dist/builder/page-files.d.ts.map +1 -0
  7. package/dist/builder/page-files.js +45 -0
  8. package/dist/builder/page-files.js.map +1 -0
  9. package/dist/builder/public-env.d.ts +2 -0
  10. package/dist/builder/public-env.d.ts.map +1 -0
  11. package/dist/builder/public-env.js +5 -0
  12. package/dist/builder/public-env.js.map +1 -0
  13. package/dist/builder/rspack-config.d.ts +14 -0
  14. package/dist/builder/rspack-config.d.ts.map +1 -0
  15. package/dist/builder/rspack-config.js +235 -0
  16. package/dist/builder/rspack-config.js.map +1 -0
  17. package/dist/cli/build.d.ts +11 -0
  18. package/dist/cli/build.d.ts.map +1 -0
  19. package/dist/cli/build.js +64 -0
  20. package/dist/cli/build.js.map +1 -0
  21. package/dist/cli/dev.d.ts +9 -0
  22. package/dist/cli/dev.d.ts.map +1 -0
  23. package/dist/cli/dev.js +210 -0
  24. package/dist/cli/dev.js.map +1 -0
  25. package/dist/cli/index.d.ts +2 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/index.js +77 -0
  28. package/dist/cli/index.js.map +1 -0
  29. package/dist/cli/start.d.ts +8 -0
  30. package/dist/cli/start.d.ts.map +1 -0
  31. package/dist/cli/start.js +39 -0
  32. package/dist/cli/start.js.map +1 -0
  33. package/dist/config.d.ts +121 -0
  34. package/dist/config.d.ts.map +1 -0
  35. package/dist/config.js +5 -0
  36. package/dist/config.js.map +1 -0
  37. package/dist/deploy/aws-lambda/runtime.d.ts +14 -0
  38. package/dist/deploy/aws-lambda/runtime.d.ts.map +1 -0
  39. package/dist/deploy/aws-lambda/runtime.js +24 -0
  40. package/dist/deploy/aws-lambda/runtime.js.map +1 -0
  41. package/dist/deploy/build-marker.d.ts +15 -0
  42. package/dist/deploy/build-marker.d.ts.map +1 -0
  43. package/dist/deploy/build-marker.js +26 -0
  44. package/dist/deploy/build-marker.js.map +1 -0
  45. package/dist/deploy/bun/runtime.d.ts +11 -0
  46. package/dist/deploy/bun/runtime.d.ts.map +1 -0
  47. package/dist/deploy/bun/runtime.js +22 -0
  48. package/dist/deploy/bun/runtime.js.map +1 -0
  49. package/dist/deploy/cloudflare/build.d.ts +7 -0
  50. package/dist/deploy/cloudflare/build.d.ts.map +1 -0
  51. package/dist/deploy/cloudflare/build.js +74 -0
  52. package/dist/deploy/cloudflare/build.js.map +1 -0
  53. package/dist/deploy/cloudflare/runtime.d.ts +10 -0
  54. package/dist/deploy/cloudflare/runtime.d.ts.map +1 -0
  55. package/dist/deploy/cloudflare/runtime.js +129 -0
  56. package/dist/deploy/cloudflare/runtime.js.map +1 -0
  57. package/dist/deploy/contract.d.ts +65 -0
  58. package/dist/deploy/contract.d.ts.map +1 -0
  59. package/dist/deploy/contract.js +2 -0
  60. package/dist/deploy/contract.js.map +1 -0
  61. package/dist/deploy/deno/runtime.d.ts +11 -0
  62. package/dist/deploy/deno/runtime.d.ts.map +1 -0
  63. package/dist/deploy/deno/runtime.js +16 -0
  64. package/dist/deploy/deno/runtime.js.map +1 -0
  65. package/dist/deploy/filesystem.d.ts +10 -0
  66. package/dist/deploy/filesystem.d.ts.map +1 -0
  67. package/dist/deploy/filesystem.js +47 -0
  68. package/dist/deploy/filesystem.js.map +1 -0
  69. package/dist/deploy/listen.d.ts +20 -0
  70. package/dist/deploy/listen.d.ts.map +1 -0
  71. package/dist/deploy/listen.js +24 -0
  72. package/dist/deploy/listen.js.map +1 -0
  73. package/dist/deploy/netlify/build.d.ts +8 -0
  74. package/dist/deploy/netlify/build.d.ts.map +1 -0
  75. package/dist/deploy/netlify/build.js +52 -0
  76. package/dist/deploy/netlify/build.js.map +1 -0
  77. package/dist/deploy/netlify/runtime.d.ts +13 -0
  78. package/dist/deploy/netlify/runtime.d.ts.map +1 -0
  79. package/dist/deploy/netlify/runtime.js +24 -0
  80. package/dist/deploy/netlify/runtime.js.map +1 -0
  81. package/dist/deploy/node/runtime.d.ts +7 -0
  82. package/dist/deploy/node/runtime.d.ts.map +1 -0
  83. package/dist/deploy/node/runtime.js +36 -0
  84. package/dist/deploy/node/runtime.js.map +1 -0
  85. package/dist/deploy/presets.d.ts +88 -0
  86. package/dist/deploy/presets.d.ts.map +1 -0
  87. package/dist/deploy/presets.js +110 -0
  88. package/dist/deploy/presets.js.map +1 -0
  89. package/dist/deploy/vercel/build.d.ts +3 -0
  90. package/dist/deploy/vercel/build.d.ts.map +1 -0
  91. package/dist/deploy/vercel/build.js +56 -0
  92. package/dist/deploy/vercel/build.js.map +1 -0
  93. package/dist/deploy/vercel/runtime.d.ts +14 -0
  94. package/dist/deploy/vercel/runtime.d.ts.map +1 -0
  95. package/dist/deploy/vercel/runtime.js +26 -0
  96. package/dist/deploy/vercel/runtime.js.map +1 -0
  97. package/dist/index.d.ts +23 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +17 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/router.d.ts +337 -0
  102. package/dist/router.d.ts.map +1 -0
  103. package/dist/router.js +18 -0
  104. package/dist/router.js.map +1 -0
  105. package/dist/runtime/boundaries.d.ts +102 -0
  106. package/dist/runtime/boundaries.d.ts.map +1 -0
  107. package/dist/runtime/boundaries.js +101 -0
  108. package/dist/runtime/boundaries.js.map +1 -0
  109. package/dist/runtime/client.d.ts +16 -0
  110. package/dist/runtime/client.d.ts.map +1 -0
  111. package/dist/runtime/client.js +16 -0
  112. package/dist/runtime/client.js.map +1 -0
  113. package/dist/runtime/context.d.ts +271 -0
  114. package/dist/runtime/context.d.ts.map +1 -0
  115. package/dist/runtime/context.js +360 -0
  116. package/dist/runtime/context.js.map +1 -0
  117. package/dist/runtime/control.d.ts +18 -0
  118. package/dist/runtime/control.d.ts.map +1 -0
  119. package/dist/runtime/control.js +39 -0
  120. package/dist/runtime/control.js.map +1 -0
  121. package/dist/runtime/dev-protocol.d.ts +22 -0
  122. package/dist/runtime/dev-protocol.d.ts.map +1 -0
  123. package/dist/runtime/dev-protocol.js +2 -0
  124. package/dist/runtime/dev-protocol.js.map +1 -0
  125. package/dist/runtime/empty-server-app.d.ts +3 -0
  126. package/dist/runtime/empty-server-app.d.ts.map +1 -0
  127. package/dist/runtime/empty-server-app.js +2 -0
  128. package/dist/runtime/empty-server-app.js.map +1 -0
  129. package/dist/runtime/entry.client.d.ts +2 -0
  130. package/dist/runtime/entry.client.d.ts.map +1 -0
  131. package/dist/runtime/entry.client.js +453 -0
  132. package/dist/runtime/entry.client.js.map +1 -0
  133. package/dist/runtime/entry.rsc.d.ts +32 -0
  134. package/dist/runtime/entry.rsc.d.ts.map +1 -0
  135. package/dist/runtime/entry.rsc.js +466 -0
  136. package/dist/runtime/entry.rsc.js.map +1 -0
  137. package/dist/runtime/entry.ssr.d.ts +25 -0
  138. package/dist/runtime/entry.ssr.d.ts.map +1 -0
  139. package/dist/runtime/entry.ssr.js +86 -0
  140. package/dist/runtime/entry.ssr.js.map +1 -0
  141. package/dist/runtime/navigation.d.ts +114 -0
  142. package/dist/runtime/navigation.d.ts.map +1 -0
  143. package/dist/runtime/navigation.js +112 -0
  144. package/dist/runtime/navigation.js.map +1 -0
  145. package/dist/runtime/request.d.ts +35 -0
  146. package/dist/runtime/request.d.ts.map +1 -0
  147. package/dist/runtime/request.js +39 -0
  148. package/dist/runtime/request.js.map +1 -0
  149. package/dist/runtime/server.d.ts +24 -0
  150. package/dist/runtime/server.d.ts.map +1 -0
  151. package/dist/runtime/server.js +24 -0
  152. package/dist/runtime/server.js.map +1 -0
  153. package/dist/server/compress.d.ts +15 -0
  154. package/dist/server/compress.d.ts.map +1 -0
  155. package/dist/server/compress.js +76 -0
  156. package/dist/server/compress.js.map +1 -0
  157. package/dist/server/headers.d.ts +24 -0
  158. package/dist/server/headers.d.ts.map +1 -0
  159. package/dist/server/headers.js +44 -0
  160. package/dist/server/headers.js.map +1 -0
  161. package/dist/server/load-config.d.ts +7 -0
  162. package/dist/server/load-config.d.ts.map +1 -0
  163. package/dist/server/load-config.js +41 -0
  164. package/dist/server/load-config.js.map +1 -0
  165. package/dist/server/load-env.d.ts +2 -0
  166. package/dist/server/load-env.d.ts.map +1 -0
  167. package/dist/server/load-env.js +10 -0
  168. package/dist/server/load-env.js.map +1 -0
  169. package/dist/server/prerendered.d.ts +67 -0
  170. package/dist/server/prerendered.d.ts.map +1 -0
  171. package/dist/server/prerendered.js +39 -0
  172. package/dist/server/prerendered.js.map +1 -0
  173. package/dist/server/server-config.d.ts +72 -0
  174. package/dist/server/server-config.d.ts.map +1 -0
  175. package/dist/server/server-config.js +94 -0
  176. package/dist/server/server-config.js.map +1 -0
  177. package/dist/server/shutdown.d.ts +7 -0
  178. package/dist/server/shutdown.d.ts.map +1 -0
  179. package/dist/server/shutdown.js +11 -0
  180. package/dist/server/shutdown.js.map +1 -0
  181. package/dist/server/ssg.d.ts +25 -0
  182. package/dist/server/ssg.d.ts.map +1 -0
  183. package/dist/server/ssg.js +160 -0
  184. package/dist/server/ssg.js.map +1 -0
  185. package/dist/server/static.d.ts +14 -0
  186. package/dist/server/static.d.ts.map +1 -0
  187. package/dist/server/static.js +30 -0
  188. package/dist/server/static.js.map +1 -0
  189. package/package.json +86 -0
@@ -0,0 +1,24 @@
1
+ /**
2
+ * `@rshono/core/server` — the request-scoped surface, for use inside server components
3
+ * and `'use server'` action modules: {@link getContext} for the URL, cookies,
4
+ * params, env and middleware variables, the {@link redirect} and {@link notFound}
5
+ * control-flow helpers, and {@link onServerError} for reporting the errors the
6
+ * framework catches.
7
+ *
8
+ * Server-only. Importing this from a `'use client'` module is a mistake — those
9
+ * run in the browser (and are SSR'd without a bound context). Read what you need
10
+ * on the server and pass it down as props, or use `useNavigation()` from
11
+ * `@rshono/core/client` for URL data.
12
+ *
13
+ * A barrel rather than `./context.js` itself, which is where all of this is
14
+ * implemented: that module also exports the plumbing the framework's own entry
15
+ * points need (`runWithContext`, `readParams`, `publicUrl`, `reportServerError`),
16
+ * and pointing the `./server` subpath straight at it published every one of them —
17
+ * `@internal` in the docs, but present in a consumer's autocomplete and pinned by
18
+ * semver all the same. They stay reachable by relative import, which is the only
19
+ * way the framework itself ever reaches them.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+ export { getContext, notFound, onServerError, redirect, } from './context.js';
24
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/runtime/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,aAAa,EACb,QAAQ,GAST,MAAM,cAAc,CAAC","sourcesContent":["/**\n * `@rshono/core/server` — the request-scoped surface, for use inside server components\n * and `'use server'` action modules: {@link getContext} for the URL, cookies,\n * params, env and middleware variables, the {@link redirect} and {@link notFound}\n * control-flow helpers, and {@link onServerError} for reporting the errors the\n * framework catches.\n *\n * Server-only. Importing this from a `'use client'` module is a mistake — those\n * run in the browser (and are SSR'd without a bound context). Read what you need\n * on the server and pass it down as props, or use `useNavigation()` from\n * `@rshono/core/client` for URL data.\n *\n * A barrel rather than `./context.js` itself, which is where all of this is\n * implemented: that module also exports the plumbing the framework's own entry\n * points need (`runWithContext`, `readParams`, `publicUrl`, `reportServerError`),\n * and pointing the `./server` subpath straight at it published every one of them —\n * `@internal` in the docs, but present in a consumer's autocomplete and pinned by\n * semver all the same. They stay reachable by relative import, which is the only\n * way the framework itself ever reaches them.\n *\n * @packageDocumentation\n */\n\nexport {\n getContext,\n notFound,\n onServerError,\n redirect,\n // A type, not a value: `Ctx` is handed to you by `getContext()` or the `ctx` page\n // prop — one instance per request — and is never constructed by application code.\n type Ctx,\n type EnvVars,\n type RedirectStatus,\n type ServerErrorContext,\n type ServerErrorHandler,\n type ServerErrorSource,\n} from './context.js';\n"]}
@@ -0,0 +1,15 @@
1
+ import type { MiddlewareHandler } from 'hono';
2
+ /**
3
+ * Gzips compressible responses, **without breaking streaming**.
4
+ *
5
+ * The obvious implementation — the platform's `CompressionStream`, which Hono's own `compress`
6
+ * middleware uses — buffers: zlib holds bytes back until it has a full block, so a streamed SSR
7
+ * shell would sit in the compressor instead of reaching the browser. That defeats the entire point
8
+ * of streaming a page. Node's zlib with `Z_SYNC_FLUSH` instead ends every write at a byte boundary
9
+ * the client can decode immediately, so each chunk the renderer flushes is a chunk the browser
10
+ * receives, at the cost of a few bytes of framing per chunk.
11
+ *
12
+ * Registered as the outermost middleware so it sees the finished response, headers and all.
13
+ */
14
+ export declare function compress(): MiddlewareHandler;
15
+ //# sourceMappingURL=compress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../../src/server/compress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AA0B9C;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAsC5C"}
@@ -0,0 +1,76 @@
1
+ import { COMPRESSIBLE_CONTENT_TYPE_REGEX } from 'hono/utils/compress';
2
+ import { Duplex } from 'node:stream';
3
+ import { constants, createGzip } from 'node:zlib';
4
+ import { appendVary } from './headers.js';
5
+ /** Below this many uncompressed bytes the gzip framing costs more than it saves. Only applied when the length is known up front. */
6
+ const COMPRESSION_THRESHOLD_BYTES = 1024;
7
+ /** `Cache-Control: no-transform` is a proxy asking not to be re-encoded; honour it. */
8
+ const NO_TRANSFORM = /(?:^|,)\s*no-transform\s*(?:,|$)/i;
9
+ /** Every browser that sends `Accept-Encoding` at all accepts gzip, so one encoding covers the field. */
10
+ function acceptsGzip(acceptEncoding) {
11
+ if (!acceptEncoding)
12
+ return false;
13
+ // No `q=` anywhere (what every real browser sends) means there is no refusal to look for.
14
+ if (!acceptEncoding.includes('q='))
15
+ return acceptEncoding.includes('gzip') || acceptEncoding.includes('*');
16
+ return acceptEncoding.split(',').some((entry) => {
17
+ const [name, ...params] = entry.trim().split(';');
18
+ if (name.toLowerCase() !== 'gzip' && name.trim() !== '*')
19
+ return false;
20
+ // `gzip;q=0` is an explicit refusal, not an offer.
21
+ const q = params.map((p) => p.trim()).find((p) => p.startsWith('q='));
22
+ return q === undefined || Number(q.slice(2)) > 0;
23
+ });
24
+ }
25
+ /**
26
+ * Gzips compressible responses, **without breaking streaming**.
27
+ *
28
+ * The obvious implementation — the platform's `CompressionStream`, which Hono's own `compress`
29
+ * middleware uses — buffers: zlib holds bytes back until it has a full block, so a streamed SSR
30
+ * shell would sit in the compressor instead of reaching the browser. That defeats the entire point
31
+ * of streaming a page. Node's zlib with `Z_SYNC_FLUSH` instead ends every write at a byte boundary
32
+ * the client can decode immediately, so each chunk the renderer flushes is a chunk the browser
33
+ * receives, at the cost of a few bytes of framing per chunk.
34
+ *
35
+ * Registered as the outermost middleware so it sees the finished response, headers and all.
36
+ */
37
+ export function compress() {
38
+ return async (c, next) => {
39
+ await next();
40
+ const res = c.res;
41
+ if (c.req.method === 'HEAD')
42
+ return;
43
+ // 204/304 have no body to speak of; a 206 range is counted in *uncompressed* bytes.
44
+ if (res.status === 204 || res.status === 304 || res.status === 206)
45
+ return;
46
+ if (res.headers.has('content-encoding'))
47
+ return;
48
+ if (!COMPRESSIBLE_CONTENT_TYPE_REGEX.test(res.headers.get('content-type') ?? ''))
49
+ return;
50
+ if (NO_TRANSFORM.test(res.headers.get('cache-control') ?? ''))
51
+ return;
52
+ const contentLength = res.headers.get('content-length');
53
+ if (contentLength !== null && Number(contentLength) < COMPRESSION_THRESHOLD_BYTES)
54
+ return;
55
+ if (!acceptsGzip(c.req.header('accept-encoding')))
56
+ return;
57
+ // Read `.body` only once we know we're compressing: it is what makes @hono/node-server's
58
+ // lightweight Response materialize a real one, throwing away the [status, body, headers] tuple
59
+ // it would otherwise write straight to the socket. The guards above touch only `.status` and
60
+ // `.headers`, which leave that fast path intact for every response we decide to pass through.
61
+ const body = res.body;
62
+ if (!body)
63
+ return;
64
+ const gzip = Duplex.toWeb(createGzip({ flush: constants.Z_SYNC_FLUSH }));
65
+ c.res = new Response(body.pipeThrough(gzip), res);
66
+ c.res.headers.set('content-encoding', 'gzip');
67
+ c.res.headers.delete('content-length'); // no longer the length of what goes on the wire
68
+ appendVary(c.res.headers, 'Accept-Encoding');
69
+ // The bytes changed, so a strong validator no longer describes them — but it is still the same
70
+ // representation, which is exactly what a weak one means.
71
+ const etag = c.res.headers.get('etag');
72
+ if (etag && !etag.startsWith('W/'))
73
+ c.res.headers.set('etag', `W/${etag}`);
74
+ };
75
+ }
76
+ //# sourceMappingURL=compress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress.js","sourceRoot":"","sources":["../../src/server/compress.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MiddlewareHandler } from 'hono';\nimport { COMPRESSIBLE_CONTENT_TYPE_REGEX } from 'hono/utils/compress';\nimport { Duplex } from 'node:stream';\nimport { constants, createGzip } from 'node:zlib';\nimport { appendVary } from './headers.js';\n\n/** Below this many uncompressed bytes the gzip framing costs more than it saves. Only applied when the length is known up front. */\nconst COMPRESSION_THRESHOLD_BYTES = 1024;\n\n/** `Cache-Control: no-transform` is a proxy asking not to be re-encoded; honour it. */\nconst NO_TRANSFORM = /(?:^|,)\\s*no-transform\\s*(?:,|$)/i;\n\n/** Every browser that sends `Accept-Encoding` at all accepts gzip, so one encoding covers the field. */\nfunction acceptsGzip(acceptEncoding: string | undefined): boolean {\n if (!acceptEncoding) return false;\n // No `q=` anywhere (what every real browser sends) means there is no refusal to look for.\n if (!acceptEncoding.includes('q=')) return acceptEncoding.includes('gzip') || acceptEncoding.includes('*');\n return acceptEncoding.split(',').some((entry) => {\n const [name, ...params] = entry.trim().split(';');\n if (name.toLowerCase() !== 'gzip' && name.trim() !== '*') return false;\n // `gzip;q=0` is an explicit refusal, not an offer.\n const q = params.map((p) => p.trim()).find((p) => p.startsWith('q='));\n return q === undefined || Number(q.slice(2)) > 0;\n });\n}\n\n/**\n * Gzips compressible responses, **without breaking streaming**.\n *\n * The obvious implementation — the platform's `CompressionStream`, which Hono's own `compress`\n * middleware uses — buffers: zlib holds bytes back until it has a full block, so a streamed SSR\n * shell would sit in the compressor instead of reaching the browser. That defeats the entire point\n * of streaming a page. Node's zlib with `Z_SYNC_FLUSH` instead ends every write at a byte boundary\n * the client can decode immediately, so each chunk the renderer flushes is a chunk the browser\n * receives, at the cost of a few bytes of framing per chunk.\n *\n * Registered as the outermost middleware so it sees the finished response, headers and all.\n */\nexport function compress(): MiddlewareHandler {\n return async (c, next) => {\n await next();\n\n const res = c.res;\n if (c.req.method === 'HEAD') return;\n // 204/304 have no body to speak of; a 206 range is counted in *uncompressed* bytes.\n if (res.status === 204 || res.status === 304 || res.status === 206) return;\n if (res.headers.has('content-encoding')) return;\n if (!COMPRESSIBLE_CONTENT_TYPE_REGEX.test(res.headers.get('content-type') ?? '')) return;\n if (NO_TRANSFORM.test(res.headers.get('cache-control') ?? '')) return;\n\n const contentLength = res.headers.get('content-length');\n if (contentLength !== null && Number(contentLength) < COMPRESSION_THRESHOLD_BYTES) return;\n if (!acceptsGzip(c.req.header('accept-encoding'))) return;\n\n // Read `.body` only once we know we're compressing: it is what makes @hono/node-server's\n // lightweight Response materialize a real one, throwing away the [status, body, headers] tuple\n // it would otherwise write straight to the socket. The guards above touch only `.status` and\n // `.headers`, which leave that fast path intact for every response we decide to pass through.\n const body = res.body;\n if (!body) return;\n\n const gzip = Duplex.toWeb(createGzip({ flush: constants.Z_SYNC_FLUSH })) as unknown as {\n readable: ReadableStream<Uint8Array>;\n writable: WritableStream<Uint8Array>;\n };\n\n c.res = new Response(body.pipeThrough(gzip), res);\n c.res.headers.set('content-encoding', 'gzip');\n c.res.headers.delete('content-length'); // no longer the length of what goes on the wire\n appendVary(c.res.headers, 'Accept-Encoding');\n\n // The bytes changed, so a strong validator no longer describes them — but it is still the same\n // representation, which is exactly what a weak one means.\n const etag = c.res.headers.get('etag');\n if (etag && !etag.startsWith('W/')) c.res.headers.set('etag', `W/${etag}`);\n };\n}\n"]}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Small header utilities shared by the response-header defaults, the compressor and the
3
+ * prerendered-page cache. Kept apart from any one of them because getting `Vary` and `ETag`
4
+ * comparison subtly wrong is exactly the kind of thing that only shows up behind a CDN.
5
+ */
6
+ /**
7
+ * Adds `value` to the `Vary` header without discarding what is already there.
8
+ *
9
+ * `Vary` is a list, and two different concerns write to it here — content negotiation on `Accept`
10
+ * (HTML document vs flight payload) and `Accept-Encoding` from the compressor. A plain `set` from
11
+ * whichever ran last would drop the other, and a cache would then happily serve one variant in
12
+ * place of the other. `*` is left alone: it already means "never reuse this".
13
+ */
14
+ export declare function appendVary(headers: Headers, value: string): void;
15
+ /**
16
+ * True when an `If-None-Match` request header matches `etag`, i.e. the client already holds this
17
+ * exact body and should be answered with a 304.
18
+ *
19
+ * The header carries a *list*, and each entry may be weak (`W/"…"`). The weak prefix is ignored on
20
+ * both sides because the compressor rewrites a strong tag to a weak one when it changes the bytes
21
+ * on the wire — the representation is still the same one the client cached.
22
+ */
23
+ export declare function etagMatches(ifNoneMatch: string | undefined, etag: string): boolean;
24
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../../src/server/headers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAShE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQlF"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Small header utilities shared by the response-header defaults, the compressor and the
3
+ * prerendered-page cache. Kept apart from any one of them because getting `Vary` and `ETag`
4
+ * comparison subtly wrong is exactly the kind of thing that only shows up behind a CDN.
5
+ */
6
+ /**
7
+ * Adds `value` to the `Vary` header without discarding what is already there.
8
+ *
9
+ * `Vary` is a list, and two different concerns write to it here — content negotiation on `Accept`
10
+ * (HTML document vs flight payload) and `Accept-Encoding` from the compressor. A plain `set` from
11
+ * whichever ran last would drop the other, and a cache would then happily serve one variant in
12
+ * place of the other. `*` is left alone: it already means "never reuse this".
13
+ */
14
+ export function appendVary(headers, value) {
15
+ const existing = headers.get('vary');
16
+ if (existing === null) {
17
+ headers.set('vary', value);
18
+ return;
19
+ }
20
+ if (existing.trim() === '*')
21
+ return;
22
+ const already = existing.split(',').some((entry) => entry.trim().toLowerCase() === value.toLowerCase());
23
+ if (!already)
24
+ headers.set('vary', `${existing}, ${value}`);
25
+ }
26
+ /**
27
+ * True when an `If-None-Match` request header matches `etag`, i.e. the client already holds this
28
+ * exact body and should be answered with a 304.
29
+ *
30
+ * The header carries a *list*, and each entry may be weak (`W/"…"`). The weak prefix is ignored on
31
+ * both sides because the compressor rewrites a strong tag to a weak one when it changes the bytes
32
+ * on the wire — the representation is still the same one the client cached.
33
+ */
34
+ export function etagMatches(ifNoneMatch, etag) {
35
+ if (!ifNoneMatch)
36
+ return false;
37
+ const normalize = (value) => value.trim().replace(/^W\//, '');
38
+ const wanted = normalize(etag);
39
+ return ifNoneMatch.split(',').some((entry) => {
40
+ const candidate = normalize(entry);
41
+ return candidate === '*' || candidate === wanted;
42
+ });
43
+ }
44
+ //# sourceMappingURL=headers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.js","sourceRoot":"","sources":["../../src/server/headers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,OAAgB,EAAE,KAAa;IACxD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG;QAAE,OAAO;IACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IACxG,IAAI,CAAC,OAAO;QAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,QAAQ,KAAK,KAAK,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,WAA+B,EAAE,IAAY;IACvE,IAAI,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3C,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,OAAO,SAAS,KAAK,GAAG,IAAI,SAAS,KAAK,MAAM,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Small header utilities shared by the response-header defaults, the compressor and the\n * prerendered-page cache. Kept apart from any one of them because getting `Vary` and `ETag`\n * comparison subtly wrong is exactly the kind of thing that only shows up behind a CDN.\n */\n\n/**\n * Adds `value` to the `Vary` header without discarding what is already there.\n *\n * `Vary` is a list, and two different concerns write to it here — content negotiation on `Accept`\n * (HTML document vs flight payload) and `Accept-Encoding` from the compressor. A plain `set` from\n * whichever ran last would drop the other, and a cache would then happily serve one variant in\n * place of the other. `*` is left alone: it already means \"never reuse this\".\n */\nexport function appendVary(headers: Headers, value: string): void {\n const existing = headers.get('vary');\n if (existing === null) {\n headers.set('vary', value);\n return;\n }\n if (existing.trim() === '*') return;\n const already = existing.split(',').some((entry) => entry.trim().toLowerCase() === value.toLowerCase());\n if (!already) headers.set('vary', `${existing}, ${value}`);\n}\n\n/**\n * True when an `If-None-Match` request header matches `etag`, i.e. the client already holds this\n * exact body and should be answered with a 304.\n *\n * The header carries a *list*, and each entry may be weak (`W/\"…\"`). The weak prefix is ignored on\n * both sides because the compressor rewrites a strong tag to a weak one when it changes the bytes\n * on the wire — the representation is still the same one the client cached.\n */\nexport function etagMatches(ifNoneMatch: string | undefined, etag: string): boolean {\n if (!ifNoneMatch) return false;\n const normalize = (value: string) => value.trim().replace(/^W\\//, '');\n const wanted = normalize(etag);\n return ifNoneMatch.split(',').some((entry) => {\n const candidate = normalize(entry);\n return candidate === '*' || candidate === wanted;\n });\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { RSHonoConfig } from '../config.js';
2
+ /**
3
+ * Load the project config, or `{}` if none exists. Scans `rshono.config.{ts,js,mjs}` at
4
+ * {@link rootDir} unless an explicit {@link configPath} is given (resolved relative to `cwd`).
5
+ */
6
+ export declare function loadConfig(rootDir: string, configPath?: string): Promise<RSHonoConfig>;
7
+ //# sourceMappingURL=load-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-config.d.ts","sourceRoot":"","sources":["../../src/server/load-config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAmBjD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAe5F"}
@@ -0,0 +1,41 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { isAbsolute, join, resolve } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ const CONFIG_FILES = ['rshono.config.ts', 'rshono.config.js', 'rshono.config.mjs'];
5
+ /**
6
+ * Imports the config module.
7
+ *
8
+ * A `.js`/`.mjs` config is a plain dynamic import. A `.ts` one can't be — the CLI itself runs as
9
+ * compiled JavaScript, so nothing in the process understands TypeScript by default. `tsx`'s
10
+ * programmatic API is loaded for that case only, which keeps it off the startup path of every
11
+ * other command instead of paying for a TypeScript loader the whole CLI doesn't need.
12
+ */
13
+ async function importConfig(file) {
14
+ const href = pathToFileURL(file).href;
15
+ if (!/\.[cm]?ts$/.test(file))
16
+ return import(href);
17
+ const { tsImport } = await import('tsx/esm/api');
18
+ return tsImport(href, import.meta.url);
19
+ }
20
+ /**
21
+ * Load the project config, or `{}` if none exists. Scans `rshono.config.{ts,js,mjs}` at
22
+ * {@link rootDir} unless an explicit {@link configPath} is given (resolved relative to `cwd`).
23
+ */
24
+ export async function loadConfig(rootDir, configPath) {
25
+ const file = configPath
26
+ ? isAbsolute(configPath)
27
+ ? configPath
28
+ : resolve(process.cwd(), configPath)
29
+ : CONFIG_FILES.map((f) => join(rootDir, f)).find(existsSync);
30
+ if (!file)
31
+ return {};
32
+ if (!existsSync(file)) {
33
+ throw new Error(`[rshono] config file not found: ${file}`);
34
+ }
35
+ const mod = await importConfig(file);
36
+ if (!mod.default) {
37
+ throw new Error(`[rshono] ${file} must \`export default\` a config object (use \`defineConfig({ … })\`).`);
38
+ }
39
+ return mod.default;
40
+ }
41
+ //# sourceMappingURL=load-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-config.js","sourceRoot":"","sources":["../../src/server/load-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,YAAY,GAAG,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,CAAC,CAAC;AAEnF;;;;;;;GAOG;AACH,KAAK,UAAU,YAAY,CAAC,IAAY;IACtC,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;IACtC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,IAAI,CAAwC,CAAC;IACzF,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACjD,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC,GAAG,CAAwC,CAAC;AAChF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,UAAmB;IACnE,MAAM,IAAI,GAAG,UAAU;QACrB,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;YACtB,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC;QACtC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/D,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,yEAAyE,CAAC,CAAC;IAC7G,CAAC;IACD,OAAO,GAAG,CAAC,OAAO,CAAC;AACrB,CAAC","sourcesContent":["import { existsSync } from 'node:fs';\nimport { isAbsolute, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { RSHonoConfig } from '../config.js';\n\nconst CONFIG_FILES = ['rshono.config.ts', 'rshono.config.js', 'rshono.config.mjs'];\n\n/**\n * Imports the config module.\n *\n * A `.js`/`.mjs` config is a plain dynamic import. A `.ts` one can't be — the CLI itself runs as\n * compiled JavaScript, so nothing in the process understands TypeScript by default. `tsx`'s\n * programmatic API is loaded for that case only, which keeps it off the startup path of every\n * other command instead of paying for a TypeScript loader the whole CLI doesn't need.\n */\nasync function importConfig(file: string): Promise<{ default?: RSHonoConfig }> {\n const href = pathToFileURL(file).href;\n if (!/\\.[cm]?ts$/.test(file)) return import(href) as Promise<{ default?: RSHonoConfig }>;\n const { tsImport } = await import('tsx/esm/api');\n return tsImport(href, import.meta.url) as Promise<{ default?: RSHonoConfig }>;\n}\n\n/**\n * Load the project config, or `{}` if none exists. Scans `rshono.config.{ts,js,mjs}` at\n * {@link rootDir} unless an explicit {@link configPath} is given (resolved relative to `cwd`).\n */\nexport async function loadConfig(rootDir: string, configPath?: string): Promise<RSHonoConfig> {\n const file = configPath\n ? isAbsolute(configPath)\n ? configPath\n : resolve(process.cwd(), configPath)\n : CONFIG_FILES.map((f) => join(rootDir, f)).find(existsSync);\n if (!file) return {};\n if (!existsSync(file)) {\n throw new Error(`[rshono] config file not found: ${file}`);\n }\n const mod = await importConfig(file);\n if (!mod.default) {\n throw new Error(`[rshono] ${file} must \\`export default\\` a config object (use \\`defineConfig({ … })\\`).`);\n }\n return mod.default;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function loadEnvFiles(rootDir: string): void;
2
+ //# sourceMappingURL=load-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-env.d.ts","sourceRoot":"","sources":["../../src/server/load-env.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlD"}
@@ -0,0 +1,10 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ export function loadEnvFiles(rootDir) {
4
+ for (const file of ['.env.local', '.env']) {
5
+ const envPath = join(rootDir, file);
6
+ if (existsSync(envPath))
7
+ process.loadEnvFile(envPath);
8
+ }
9
+ }
10
+ //# sourceMappingURL=load-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-env.js","sourceRoot":"","sources":["../../src/server/load-env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,KAAK,MAAM,IAAI,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;AACH,CAAC","sourcesContent":["import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport function loadEnvFiles(rootDir: string): void {\n for (const file of ['.env.local', '.env']) {\n const envPath = join(rootDir, file);\n if (existsSync(envPath)) process.loadEnvFile(envPath);\n }\n}\n"]}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Everything about a prerendered page that doesn't need a filesystem: where the build puts it, and
3
+ * what it looks like once read back.
4
+ *
5
+ * Split out of `ssg.ts` — which owns the writing and the reading, both through `node:fs` — because a
6
+ * deploy target without a filesystem reads the very same layout out of an asset store, and importing
7
+ * it from the fs module would drag `node:fs` and `node:crypto` into a bundle that has neither.
8
+ */
9
+ /**
10
+ * The two representations of a page, prerendered side by side.
11
+ *
12
+ * A hard load wants the HTML document; a soft navigation asks the same URL for a flight payload.
13
+ * Writing only the HTML meant every in-app click re-rendered a page that was already built, so the
14
+ * prerender only ever paid off for cold loads and crawlers.
15
+ */
16
+ export type PrerenderVariant = 'html' | 'flight';
17
+ export declare const VARIANTS: {
18
+ readonly html: {
19
+ readonly file: 'index.html';
20
+ readonly accept: 'text/html';
21
+ readonly contentType: 'text/html';
22
+ };
23
+ readonly flight: {
24
+ readonly file: 'index.rsc';
25
+ readonly accept: 'text/x-component';
26
+ readonly contentType: 'text/x-component';
27
+ };
28
+ };
29
+ /**
30
+ * Where a route's prerendered output lives, relative to the output root — or `null` for a path that
31
+ * cannot be prerendered at all (one with a param or a wildcard left in it).
32
+ *
33
+ * Always `/`-separated, never the host's separator: the same string addresses a file on a filesystem
34
+ * (`resolve()` and `join()` both accept forward slashes on Windows) and a key in an asset store,
35
+ * where a backslash would simply be the wrong character.
36
+ */
37
+ export declare function ssgFilePath(routePath: string, variant?: PrerenderVariant): string | null;
38
+ /**
39
+ * {@link ssgFilePath} for a path that came off a request, so traversal is a miss rather than a lookup.
40
+ *
41
+ * The first line of defence for every deploy target: a store addressed by key has no `resolve()` to
42
+ * fall back on, so `..` has to be refused here or not at all.
43
+ */
44
+ export declare function prerenderedRelPath(requestPath: string, variant: PrerenderVariant): string | null;
45
+ /** A prerendered page, ready to serve: its body and a validator derived from those exact bytes. */
46
+ export interface PrerenderedPage {
47
+ /** The document or the flight payload, depending on which {@link PrerenderVariant} was read. */
48
+ body: string;
49
+ /**
50
+ * `Content-Length` for {@link body}, in bytes rather than characters.
51
+ *
52
+ * Served with the response because Hono sets no length for an in-memory body, and without one the
53
+ * compressor cannot tell a 300-byte page from a 300 KB one — so it gzips both, including the ones
54
+ * where the framing costs more than it saves.
55
+ */
56
+ contentLength: string;
57
+ /**
58
+ * `ETag` for the page, so a revalidating client can be answered with a 304 instead of the body.
59
+ *
60
+ * Deliberately **weak**. The bytes on the wire depend on whether the client took gzip, and a
61
+ * strong validator would have to differ between those two — so the 200 and the 304 that
62
+ * revalidates it would disagree, and a cache would treat them as different pages. A weak tag
63
+ * says "the same representation", which is exactly what is true across content codings.
64
+ */
65
+ etag: string;
66
+ }
67
+ //# sourceMappingURL=prerendered.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerendered.d.ts","sourceRoot":"","sources":["../../src/server/prerendered.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEjD,eAAO,MAAM,QAAQ;;iBACX,IAAI,EAAE,YAAY;iBAAE,MAAM,EAAE,WAAW;iBAAE,WAAW,EAAE,WAAW;;;iBAC/D,IAAI,EAAE,WAAW;iBAAE,MAAM,EAAE,kBAAkB;iBAAE,WAAW,EAAE,kBAAkB;;CACU,CAAC;AAErG;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAyB,GAAG,MAAM,GAAG,IAAI,CAKhG;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CAGhG;AAED,mGAAmG;AACnG,MAAM,WAAW,eAAe;IAC9B,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Everything about a prerendered page that doesn't need a filesystem: where the build puts it, and
3
+ * what it looks like once read back.
4
+ *
5
+ * Split out of `ssg.ts` — which owns the writing and the reading, both through `node:fs` — because a
6
+ * deploy target without a filesystem reads the very same layout out of an asset store, and importing
7
+ * it from the fs module would drag `node:fs` and `node:crypto` into a bundle that has neither.
8
+ */
9
+ export const VARIANTS = {
10
+ html: { file: 'index.html', accept: 'text/html', contentType: 'text/html' },
11
+ flight: { file: 'index.rsc', accept: 'text/x-component', contentType: 'text/x-component' },
12
+ };
13
+ /**
14
+ * Where a route's prerendered output lives, relative to the output root — or `null` for a path that
15
+ * cannot be prerendered at all (one with a param or a wildcard left in it).
16
+ *
17
+ * Always `/`-separated, never the host's separator: the same string addresses a file on a filesystem
18
+ * (`resolve()` and `join()` both accept forward slashes on Windows) and a key in an asset store,
19
+ * where a backslash would simply be the wrong character.
20
+ */
21
+ export function ssgFilePath(routePath, variant = 'html') {
22
+ if (/[:*]/.test(routePath))
23
+ return null;
24
+ const trimmed = routePath.replace(/^\/+|\/+$/g, '');
25
+ const file = VARIANTS[variant].file;
26
+ return trimmed === '' ? file : `${trimmed}/${file}`;
27
+ }
28
+ /**
29
+ * {@link ssgFilePath} for a path that came off a request, so traversal is a miss rather than a lookup.
30
+ *
31
+ * The first line of defence for every deploy target: a store addressed by key has no `resolve()` to
32
+ * fall back on, so `..` has to be refused here or not at all.
33
+ */
34
+ export function prerenderedRelPath(requestPath, variant) {
35
+ if (/(^|\/)\.\.?(\/|$)/.test(requestPath))
36
+ return null;
37
+ return ssgFilePath(requestPath, variant);
38
+ }
39
+ //# sourceMappingURL=prerendered.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prerendered.js","sourceRoot":"","sources":["../../src/server/prerendered.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE;IAC3E,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,WAAW,EAAE,kBAAkB,EAAE;CACQ,CAAC;AAErG;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,OAAO,GAAqB,MAAM;IAC/E,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;IACpC,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB,EAAE,OAAyB;IAC/E,IAAI,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,OAAO,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC","sourcesContent":["/**\n * Everything about a prerendered page that doesn't need a filesystem: where the build puts it, and\n * what it looks like once read back.\n *\n * Split out of `ssg.ts` — which owns the writing and the reading, both through `node:fs` — because a\n * deploy target without a filesystem reads the very same layout out of an asset store, and importing\n * it from the fs module would drag `node:fs` and `node:crypto` into a bundle that has neither.\n */\n\n/**\n * The two representations of a page, prerendered side by side.\n *\n * A hard load wants the HTML document; a soft navigation asks the same URL for a flight payload.\n * Writing only the HTML meant every in-app click re-rendered a page that was already built, so the\n * prerender only ever paid off for cold loads and crawlers.\n */\nexport type PrerenderVariant = 'html' | 'flight';\n\nexport const VARIANTS = {\n html: { file: 'index.html', accept: 'text/html', contentType: 'text/html' },\n flight: { file: 'index.rsc', accept: 'text/x-component', contentType: 'text/x-component' },\n} as const satisfies Record<PrerenderVariant, { file: string; accept: string; contentType: string }>;\n\n/**\n * Where a route's prerendered output lives, relative to the output root — or `null` for a path that\n * cannot be prerendered at all (one with a param or a wildcard left in it).\n *\n * Always `/`-separated, never the host's separator: the same string addresses a file on a filesystem\n * (`resolve()` and `join()` both accept forward slashes on Windows) and a key in an asset store,\n * where a backslash would simply be the wrong character.\n */\nexport function ssgFilePath(routePath: string, variant: PrerenderVariant = 'html'): string | null {\n if (/[:*]/.test(routePath)) return null;\n const trimmed = routePath.replace(/^\\/+|\\/+$/g, '');\n const file = VARIANTS[variant].file;\n return trimmed === '' ? file : `${trimmed}/${file}`;\n}\n\n/**\n * {@link ssgFilePath} for a path that came off a request, so traversal is a miss rather than a lookup.\n *\n * The first line of defence for every deploy target: a store addressed by key has no `resolve()` to\n * fall back on, so `..` has to be refused here or not at all.\n */\nexport function prerenderedRelPath(requestPath: string, variant: PrerenderVariant): string | null {\n if (/(^|\\/)\\.\\.?(\\/|$)/.test(requestPath)) return null;\n return ssgFilePath(requestPath, variant);\n}\n\n/** A prerendered page, ready to serve: its body and a validator derived from those exact bytes. */\nexport interface PrerenderedPage {\n /** The document or the flight payload, depending on which {@link PrerenderVariant} was read. */\n body: string;\n /**\n * `Content-Length` for {@link body}, in bytes rather than characters.\n *\n * Served with the response because Hono sets no length for an in-memory body, and without one the\n * compressor cannot tell a 300-byte page from a 300 KB one — so it gzips both, including the ones\n * where the framing costs more than it saves.\n */\n contentLength: string;\n /**\n * `ETag` for the page, so a revalidating client can be answered with a 304 instead of the body.\n *\n * Deliberately **weak**. The bytes on the wire depend on whether the client took gzip, and a\n * strong validator would have to differ between those two — so the 200 and the 304 that\n * revalidates it would disagree, and a cache would treat them as different pages. A weak tag\n * says \"the same representation\", which is exactly what is true across content codings.\n */\n etag: string;\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import type { RSHonoConfig } from '../config.js';
2
+ /**
3
+ * The framework settings the server bundle needs at request time, fully resolved
4
+ * (defaults applied, `bodySizeLimit` parsed to bytes, origins normalized to hosts).
5
+ *
6
+ * The value is produced once by {@link resolveServerConfig} from `rshono.config.ts`
7
+ * and compiled into the server bundle as the `__RSHONO_CONFIG__` literal (see
8
+ * `builder/rspack-config.ts`) — there is no runtime env-var interface for these.
9
+ */
10
+ export interface ServerConfig {
11
+ /**
12
+ * `true` when the bundle came from `rshono dev`.
13
+ *
14
+ * Baked in rather than read from `process.env.NODE_ENV` at runtime: it is decided by which command
15
+ * produced the bundle, and a deploy target need not have a `process` to read it from.
16
+ */
17
+ isDev: boolean;
18
+ /** Deadline in ms for a single request (server action + flight + SSR). */
19
+ renderTimeoutMs: number;
20
+ /** Honour `X-Forwarded-Host` / `-Proto` when resolving the browser-facing URL. Forced on in dev. */
21
+ trustProxy: boolean;
22
+ /** Send a strict per-request-nonce Content-Security-Policy with every HTML document. */
23
+ cspEnabled: boolean;
24
+ /** The resolved CSP directives (built-in defaults with the user's merged over them), minus the nonce. */
25
+ cspDirectives: Record<string, string>;
26
+ /** CSRF origin check on server-action POSTs. */
27
+ checkOrigin: boolean;
28
+ /** Extra origins allowed to post server actions, normalized to lowercase `URL.host` values. */
29
+ allowedOrigins: string[];
30
+ /** Max request body in bytes before a 413; `0` disables the cap. */
31
+ maxBodyBytes: number;
32
+ /** Gzip compressible responses on the way out. */
33
+ compress: boolean;
34
+ /** Default listen port for `start` (overridden by `PORT`). */
35
+ port?: number;
36
+ /** Default bind address for `start` (overridden by `HOST`). */
37
+ host?: string;
38
+ }
39
+ /**
40
+ * The single source of truth for the framework's built-in defaults.
41
+ *
42
+ * `renderTimeoutMs` and `maxBodyBytes` are resolved here, into the bundle. `port` and `host` are not:
43
+ * they stay env-overridable at runtime, so the default is applied where the address is resolved
44
+ * (`deploy/listen.ts` for a server bundle, `cli/dev.ts` for the dev server) and this is what both read.
45
+ */
46
+ export declare const SERVER_DEFAULTS: {
47
+ readonly renderTimeoutMs: 10000;
48
+ readonly maxBodyBytes: number;
49
+ readonly port: 3000;
50
+ readonly host: '0.0.0.0';
51
+ };
52
+ /**
53
+ * The built-in {@link RSHonoConfig.csp} policy, keyed by directive so
54
+ * {@link RSHonoConfig.cspDirectives} can override entries individually.
55
+ *
56
+ * `script-src` carries the per-request nonce, appended at request time (see `entry.rsc.tsx`).
57
+ * `style-src` needs `'unsafe-inline'` because React writes inline styles.
58
+ */
59
+ export declare const CSP_DEFAULTS: Record<string, string>;
60
+ /** Parse a {@link RSHonoConfig.bodySizeLimit} value into a byte count (`false`/`0` → `0`, disabling the cap). */
61
+ export declare function parseByteSize(value: string | number | false | undefined): number | undefined;
62
+ /**
63
+ * Resolve the user's {@link RSHonoConfig} into the {@link ServerConfig} baked into the bundle.
64
+ *
65
+ * `isDev` is a build-time input rather than a config field because it decides one thing the user
66
+ * shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy
67
+ * is the only way in (it sets the forwarded headers itself and binds to localhost).
68
+ */
69
+ export declare function resolveServerConfig(config: RSHonoConfig, { isDev }: {
70
+ isDev: boolean;
71
+ }): ServerConfig;
72
+ //# sourceMappingURL=server-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/server/server-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,EAAE,OAAO,CAAC;IACf,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAC;IACxB,oGAAoG;IACpG,UAAU,EAAE,OAAO,CAAC;IACpB,wFAAwF;IACxF,UAAU,EAAE,OAAO,CAAC;IACpB,yGAAyG;IACzG,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,gDAAgD;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,+FAA+F;IAC/F,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,QAAQ,EAAE,OAAO,CAAC;IAClB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;aAC1B,eAAe,EAAE,KAAM;aACvB,YAAY;aACZ,IAAI,EAAE,IAAI;aACV,IAAI,EAAE,SAAS;CACP,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAY/C,CAAC;AAIF,iHAAiH;AACjH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAS5F;AA0BD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,YAAY,CAiBrG"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The single source of truth for the framework's built-in defaults.
3
+ *
4
+ * `renderTimeoutMs` and `maxBodyBytes` are resolved here, into the bundle. `port` and `host` are not:
5
+ * they stay env-overridable at runtime, so the default is applied where the address is resolved
6
+ * (`deploy/listen.ts` for a server bundle, `cli/dev.ts` for the dev server) and this is what both read.
7
+ */
8
+ export const SERVER_DEFAULTS = {
9
+ renderTimeoutMs: 10_000,
10
+ maxBodyBytes: 1024 * 1024, // 1 MiB, matching Next.js's server-action body-size limit.
11
+ port: 3000,
12
+ host: '0.0.0.0',
13
+ };
14
+ /**
15
+ * The built-in {@link RSHonoConfig.csp} policy, keyed by directive so
16
+ * {@link RSHonoConfig.cspDirectives} can override entries individually.
17
+ *
18
+ * `script-src` carries the per-request nonce, appended at request time (see `entry.rsc.tsx`).
19
+ * `style-src` needs `'unsafe-inline'` because React writes inline styles.
20
+ */
21
+ export const CSP_DEFAULTS = {
22
+ 'default-src': "'self'",
23
+ 'script-src': "'self'",
24
+ 'style-src': "'self' 'unsafe-inline'",
25
+ 'img-src': "'self' data:",
26
+ 'connect-src': "'self'",
27
+ // Not covered by default-src, and each closes an injection route of its own: a stray <base>
28
+ // retargeting every relative URL, plugin content, framing (clickjacking), off-site form posts.
29
+ 'base-uri': "'self'",
30
+ 'object-src': "'none'",
31
+ 'frame-ancestors': "'none'",
32
+ 'form-action': "'self'",
33
+ };
34
+ const UNITS = { b: 1, kb: 1024, mb: 1024 ** 2, gb: 1024 ** 3 };
35
+ /** Parse a {@link RSHonoConfig.bodySizeLimit} value into a byte count (`false`/`0` → `0`, disabling the cap). */
36
+ export function parseByteSize(value) {
37
+ if (value === undefined)
38
+ return undefined;
39
+ if (value === false)
40
+ return 0;
41
+ if (typeof value === 'number')
42
+ return value;
43
+ const match = /^\s*(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?\s*$/i.exec(value);
44
+ if (!match) {
45
+ throw new Error(`[rshono] invalid bodySizeLimit ${JSON.stringify(value)} — use e.g. '1mb', 1048576, or false.`);
46
+ }
47
+ return Math.floor(Number(match[1]) * UNITS[(match[2] ?? 'b').toLowerCase()]);
48
+ }
49
+ /**
50
+ * Normalize a config `allowedOrigins` entry (full origin or bare host) to a lowercase `URL.host`,
51
+ * ready for a direct comparison against a parsed `Origin` header's host.
52
+ *
53
+ * A bare `host:port` has to be retried against a base, because on its own `'localhost:4000'`
54
+ * parses as the *scheme* `localhost:` with path `4000` — leaving an empty host that would
55
+ * silently never match anything. Throws rather than passing a junk entry through, so a typo
56
+ * fails the build instead of quietly disabling the allowlist entry it was meant to add.
57
+ */
58
+ function normalizeOrigin(entry) {
59
+ const host = URL.parse(entry)?.host || URL.parse(`http://${entry}`)?.host;
60
+ if (!host) {
61
+ throw new Error(`[rshono] invalid allowedOrigins entry ${JSON.stringify(entry)} — use a full origin ('https://admin.example.com') or a bare host ('localhost:4000').`);
62
+ }
63
+ return host.toLowerCase();
64
+ }
65
+ /** Drop directives the user blanked out, so `cspDirectives: { 'frame-ancestors': '' }` removes one. */
66
+ function resolveCspDirectives(overrides) {
67
+ return Object.fromEntries(Object.entries({ ...CSP_DEFAULTS, ...overrides }).filter(([, value]) => value.trim() !== ''));
68
+ }
69
+ /**
70
+ * Resolve the user's {@link RSHonoConfig} into the {@link ServerConfig} baked into the bundle.
71
+ *
72
+ * `isDev` is a build-time input rather than a config field because it decides one thing the user
73
+ * shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy
74
+ * is the only way in (it sets the forwarded headers itself and binds to localhost).
75
+ */
76
+ export function resolveServerConfig(config, { isDev }) {
77
+ return {
78
+ isDev,
79
+ renderTimeoutMs: config.renderTimeout ?? SERVER_DEFAULTS.renderTimeoutMs,
80
+ trustProxy: isDev || (config.trustProxy ?? false),
81
+ cspEnabled: config.csp ?? false,
82
+ cspDirectives: resolveCspDirectives(config.cspDirectives),
83
+ checkOrigin: config.checkOrigin ?? true,
84
+ allowedOrigins: (config.allowedOrigins ?? [])
85
+ .map((entry) => entry.trim())
86
+ .filter(Boolean)
87
+ .map(normalizeOrigin),
88
+ maxBodyBytes: parseByteSize(config.bodySizeLimit) ?? SERVER_DEFAULTS.maxBodyBytes,
89
+ compress: config.compress ?? true,
90
+ port: config.port,
91
+ host: config.host,
92
+ };
93
+ }
94
+ //# sourceMappingURL=server-config.js.map