@rshono/core 1.0.0-rc.11 → 1.0.0-rc.13

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 (145) hide show
  1. package/README.md +2 -1
  2. package/bin/rshono.mjs +3 -4
  3. package/dist/builder/env-shadow-loader.cjs +5 -5
  4. package/dist/builder/page-files.js +5 -5
  5. package/dist/builder/page-files.js.map +1 -1
  6. package/dist/builder/public-env.d.ts +5 -4
  7. package/dist/builder/public-env.d.ts.map +1 -1
  8. package/dist/builder/public-env.js +5 -4
  9. package/dist/builder/public-env.js.map +1 -1
  10. package/dist/builder/rspack-config.d.ts +10 -0
  11. package/dist/builder/rspack-config.d.ts.map +1 -1
  12. package/dist/builder/rspack-config.js +38 -40
  13. package/dist/builder/rspack-config.js.map +1 -1
  14. package/dist/cli/build.js +4 -4
  15. package/dist/cli/build.js.map +1 -1
  16. package/dist/cli/dev.d.ts.map +1 -1
  17. package/dist/cli/dev.js +50 -37
  18. package/dist/cli/dev.js.map +1 -1
  19. package/dist/cli/index.js +4 -4
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/cli/start.d.ts.map +1 -1
  22. package/dist/cli/start.js +2 -3
  23. package/dist/cli/start.js.map +1 -1
  24. package/dist/config.d.ts +28 -31
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +2 -2
  27. package/dist/config.js.map +1 -1
  28. package/dist/deploy/aws-lambda/runtime.d.ts +4 -6
  29. package/dist/deploy/aws-lambda/runtime.d.ts.map +1 -1
  30. package/dist/deploy/aws-lambda/runtime.js +5 -8
  31. package/dist/deploy/aws-lambda/runtime.js.map +1 -1
  32. package/dist/deploy/build-marker.d.ts +3 -5
  33. package/dist/deploy/build-marker.d.ts.map +1 -1
  34. package/dist/deploy/build-marker.js +3 -5
  35. package/dist/deploy/build-marker.js.map +1 -1
  36. package/dist/deploy/cloudflare/build.d.ts.map +1 -1
  37. package/dist/deploy/cloudflare/build.js +6 -10
  38. package/dist/deploy/cloudflare/build.js.map +1 -1
  39. package/dist/deploy/cloudflare/runtime.d.ts +2 -5
  40. package/dist/deploy/cloudflare/runtime.d.ts.map +1 -1
  41. package/dist/deploy/cloudflare/runtime.js +19 -32
  42. package/dist/deploy/cloudflare/runtime.js.map +1 -1
  43. package/dist/deploy/contract.d.ts +25 -42
  44. package/dist/deploy/contract.d.ts.map +1 -1
  45. package/dist/deploy/contract.js.map +1 -1
  46. package/dist/deploy/filesystem.d.ts +3 -5
  47. package/dist/deploy/filesystem.d.ts.map +1 -1
  48. package/dist/deploy/filesystem.js +12 -15
  49. package/dist/deploy/filesystem.js.map +1 -1
  50. package/dist/deploy/node/runtime.d.ts +4 -5
  51. package/dist/deploy/node/runtime.d.ts.map +1 -1
  52. package/dist/deploy/node/runtime.js +9 -15
  53. package/dist/deploy/node/runtime.js.map +1 -1
  54. package/dist/deploy/presets.d.ts +19 -29
  55. package/dist/deploy/presets.d.ts.map +1 -1
  56. package/dist/deploy/presets.js +18 -25
  57. package/dist/deploy/presets.js.map +1 -1
  58. package/dist/deploy/vercel/build.d.ts.map +1 -1
  59. package/dist/deploy/vercel/build.js +9 -12
  60. package/dist/deploy/vercel/build.js.map +1 -1
  61. package/dist/deploy/vercel/runtime.d.ts +4 -7
  62. package/dist/deploy/vercel/runtime.d.ts.map +1 -1
  63. package/dist/deploy/vercel/runtime.js +4 -7
  64. package/dist/deploy/vercel/runtime.js.map +1 -1
  65. package/dist/index.d.ts +13 -9
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +15 -12
  68. package/dist/index.js.map +1 -1
  69. package/dist/router.d.ts +65 -93
  70. package/dist/router.d.ts.map +1 -1
  71. package/dist/router.js +2 -5
  72. package/dist/router.js.map +1 -1
  73. package/dist/runtime/boundaries.d.ts +24 -30
  74. package/dist/runtime/boundaries.d.ts.map +1 -1
  75. package/dist/runtime/boundaries.js +15 -22
  76. package/dist/runtime/boundaries.js.map +1 -1
  77. package/dist/runtime/client.d.ts +16 -7
  78. package/dist/runtime/client.d.ts.map +1 -1
  79. package/dist/runtime/client.js +16 -7
  80. package/dist/runtime/client.js.map +1 -1
  81. package/dist/runtime/context.d.ts +89 -118
  82. package/dist/runtime/context.d.ts.map +1 -1
  83. package/dist/runtime/context.js +107 -167
  84. package/dist/runtime/context.js.map +1 -1
  85. package/dist/runtime/control.js +3 -3
  86. package/dist/runtime/control.js.map +1 -1
  87. package/dist/runtime/dev-protocol.d.ts +4 -8
  88. package/dist/runtime/dev-protocol.d.ts.map +1 -1
  89. package/dist/runtime/dev-protocol.js.map +1 -1
  90. package/dist/runtime/entry.client.d.ts.map +1 -1
  91. package/dist/runtime/entry.client.js +92 -120
  92. package/dist/runtime/entry.client.js.map +1 -1
  93. package/dist/runtime/entry.rsc.d.ts +5 -6
  94. package/dist/runtime/entry.rsc.d.ts.map +1 -1
  95. package/dist/runtime/entry.rsc.js +67 -122
  96. package/dist/runtime/entry.rsc.js.map +1 -1
  97. package/dist/runtime/entry.ssr.d.ts +7 -12
  98. package/dist/runtime/entry.ssr.d.ts.map +1 -1
  99. package/dist/runtime/entry.ssr.js +13 -24
  100. package/dist/runtime/entry.ssr.js.map +1 -1
  101. package/dist/runtime/flight-inject.d.ts +10 -17
  102. package/dist/runtime/flight-inject.d.ts.map +1 -1
  103. package/dist/runtime/flight-inject.js +35 -53
  104. package/dist/runtime/flight-inject.js.map +1 -1
  105. package/dist/runtime/hot-update.d.ts +45 -0
  106. package/dist/runtime/hot-update.d.ts.map +1 -0
  107. package/dist/runtime/hot-update.js +44 -0
  108. package/dist/runtime/hot-update.js.map +1 -0
  109. package/dist/runtime/navigation.d.ts +14 -19
  110. package/dist/runtime/navigation.d.ts.map +1 -1
  111. package/dist/runtime/navigation.js +9 -13
  112. package/dist/runtime/navigation.js.map +1 -1
  113. package/dist/runtime/request.d.ts +4 -6
  114. package/dist/runtime/request.d.ts.map +1 -1
  115. package/dist/runtime/request.js +2 -3
  116. package/dist/runtime/request.js.map +1 -1
  117. package/dist/runtime/server.d.ts +18 -10
  118. package/dist/runtime/server.d.ts.map +1 -1
  119. package/dist/runtime/server.js +21 -19
  120. package/dist/runtime/server.js.map +1 -1
  121. package/dist/server/headers.d.ts +8 -15
  122. package/dist/server/headers.d.ts.map +1 -1
  123. package/dist/server/headers.js +8 -15
  124. package/dist/server/headers.js.map +1 -1
  125. package/dist/server/load-config.d.ts +2 -2
  126. package/dist/server/load-config.d.ts.map +1 -1
  127. package/dist/server/load-config.js +6 -9
  128. package/dist/server/load-config.js.map +1 -1
  129. package/dist/server/prerendered.d.ts +30 -43
  130. package/dist/server/prerendered.d.ts.map +1 -1
  131. package/dist/server/prerendered.js +20 -29
  132. package/dist/server/prerendered.js.map +1 -1
  133. package/dist/server/server-config.d.ts +18 -25
  134. package/dist/server/server-config.d.ts.map +1 -1
  135. package/dist/server/server-config.js +7 -11
  136. package/dist/server/server-config.js.map +1 -1
  137. package/dist/server/shutdown.d.ts +2 -3
  138. package/dist/server/shutdown.d.ts.map +1 -1
  139. package/dist/server/shutdown.js +2 -3
  140. package/dist/server/shutdown.js.map +1 -1
  141. package/dist/server/ssg.d.ts +3 -6
  142. package/dist/server/ssg.d.ts.map +1 -1
  143. package/dist/server/ssg.js +11 -20
  144. package/dist/server/ssg.js.map +1 -1
  145. package/package.json +1 -1
@@ -1,22 +1,21 @@
1
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.
2
+ * Everything about a prerendered page that doesn't need a filesystem: where the build puts it, and what it
3
+ * looks like once read back.
4
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.
5
+ * Apart from `ssg.ts`, which does the reading and writing through `node:fs`, because a deploy target without a
6
+ * filesystem reads the same layout out of an asset store — and importing it from there would drag `node:fs`
7
+ * into a bundle that has neither.
8
8
  */
9
9
  export const VARIANTS = {
10
10
  html: { file: 'index.html', accept: 'text/html', contentType: 'text/html' },
11
11
  flight: { file: 'index.rsc', accept: 'text/x-component', contentType: 'text/x-component' },
12
12
  };
13
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).
14
+ * Where a route's prerendered output lives, relative to the output root — or `null` for a path that cannot be
15
+ * prerendered at all, one with a param or a wildcard left in it.
16
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.
17
+ * Always `/`-separated: the same string addresses a file on a filesystem, which accepts forward slashes on
18
+ * Windows too, and a key in an asset store, where a backslash would be the wrong character.
20
19
  */
21
20
  export function ssgFilePath(routePath, variant = 'html') {
22
21
  if (/[:*]/.test(routePath))
@@ -26,10 +25,8 @@ export function ssgFilePath(routePath, variant = 'html') {
26
25
  return trimmed === '' ? file : `${trimmed}/${file}`;
27
26
  }
28
27
  /**
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.
28
+ * {@link ssgFilePath} for a path that came off a request, so traversal is a miss rather than a lookup. A store
29
+ * addressed by key has no `resolve()` to fall back on, so `..` is refused here or not at all.
33
30
  */
34
31
  export function prerenderedRelPath(requestPath, variant) {
35
32
  if (/(^|\/)\.\.?(\/|$)/.test(requestPath))
@@ -37,12 +34,9 @@ export function prerenderedRelPath(requestPath, variant) {
37
34
  return ssgFilePath(requestPath, variant);
38
35
  }
39
36
  /**
40
- * A bounded, insertion-ordered cache of prerendered pages.
41
- *
42
- * Bounded so a site with thousands of prerendered pages keeps a working set rather than the whole
43
- * build in memory. Only *hits* are ever stored: caching misses would let anyone mint entries by
44
- * requesting paths that don't exist. The files are written at build time and never change while the
45
- * server is up, so an entry never needs invalidating.
37
+ * A bounded, insertion-ordered cache of prerendered pages, so a site with thousands of them keeps a working set
38
+ * rather than the whole build in memory. Only *hits* are stored — caching misses would let anyone mint entries
39
+ * by requesting paths that don't exist — and the files never change while the server is up.
46
40
  */
47
41
  export function createPageCache(max = 128) {
48
42
  const pages = new Map();
@@ -50,17 +44,15 @@ export function createPageCache(max = 128) {
50
44
  get: (key) => pages.get(key),
51
45
  set(key, page) {
52
46
  pages.set(key, page);
53
- // Insertion-ordered, so the first key is the oldest. One entry in means at most one out.
47
+ // Insertion-ordered, so the first key is the oldest.
54
48
  if (pages.size > max)
55
49
  pages.delete(pages.keys().next().value);
56
50
  },
57
51
  };
58
52
  }
59
53
  /**
60
- * A weak `ETag` for a page body — see {@link PrerenderedPage.etag} for why weak.
61
- *
62
- * Web Crypto rather than `node:crypto`, so the one implementation serves both a Node server and
63
- * `workerd`.
54
+ * A weak `ETag` for a page body — see {@link PrerenderedPage.etag} for why weak. Web Crypto rather than
55
+ * `node:crypto`, so one implementation serves both a Node server and `workerd`.
64
56
  */
65
57
  export async function weakEtag(body) {
66
58
  const digest = await crypto.subtle.digest('SHA-256', body);
@@ -71,10 +63,9 @@ export async function weakEtag(body) {
71
63
  return `W/"${base64url.slice(0, 22)}"`;
72
64
  }
73
65
  /**
74
- * Assembles a {@link PrerenderedPage} from a body just read out of the build.
75
- *
76
- * `storeEtag` is the validator the store supplied, where it has one — it already describes these
77
- * exact bytes, so it is preferred over hashing them again, and only weakened.
66
+ * Assembles a {@link PrerenderedPage} from a body just read out of the build. `storeEtag` is the validator the
67
+ * store supplied, where it has one: it already describes these exact bytes, so it is weakened rather than
68
+ * replaced by a fresh hash.
78
69
  */
79
70
  export async function toPrerenderedPage(body, storeEtag) {
80
71
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"prerendered.js","sourceRoot":"","sources":["../../src/server/prerendered.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,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;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,GAAG,GAAG;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;IACjD,OAAO;QACL,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QAC5B,GAAG,CAAC,GAAG,EAAE,IAAI;YACX,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACrB,yFAAyF;YACzF,IAAI,KAAK,CAAC,IAAI,GAAG,GAAG;gBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAM,CAAC,CAAC;QACjE,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAA6B;IAC1D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;SACnE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACtB,OAAO,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAA6B,EAAE,SAAyB;IAC9F,OAAO;QACL,IAAI;QACJ,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;QACtC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC;KAC7E,CAAC;AACJ,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: a hard load wants the HTML document, a\n * soft navigation asks the same URL for a flight payload. Without both, every in-app click would\n * re-render a page that was already built.\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/**\n * A bounded, insertion-ordered cache of prerendered pages.\n *\n * Bounded so a site with thousands of prerendered pages keeps a working set rather than the whole\n * build in memory. Only *hits* are ever stored: caching misses would let anyone mint entries by\n * requesting paths that don't exist. The files are written at build time and never change while the\n * server is up, so an entry never needs invalidating.\n */\nexport function createPageCache(max = 128): { get(key: string): PrerenderedPage | undefined; set(key: string, page: PrerenderedPage): void } {\n const pages = new Map<string, PrerenderedPage>();\n return {\n get: (key) => pages.get(key),\n set(key, page) {\n pages.set(key, page);\n // Insertion-ordered, so the first key is the oldest. One entry in means at most one out.\n if (pages.size > max) pages.delete(pages.keys().next().value!);\n },\n };\n}\n\n/**\n * A weak `ETag` for a page body — see {@link PrerenderedPage.etag} for why weak.\n *\n * Web Crypto rather than `node:crypto`, so the one implementation serves both a Node server and\n * `workerd`.\n */\nexport async function weakEtag(body: Uint8Array<ArrayBuffer>): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', body);\n const base64url = btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n return `W/\"${base64url.slice(0, 22)}\"`;\n}\n\n/**\n * Assembles a {@link PrerenderedPage} from a body just read out of the build.\n *\n * `storeEtag` is the validator the store supplied, where it has one — it already describes these\n * exact bytes, so it is preferred over hashing them again, and only weakened.\n */\nexport async function toPrerenderedPage(body: Uint8Array<ArrayBuffer>, storeEtag?: string | null): Promise<PrerenderedPage> {\n return {\n body,\n contentLength: String(body.byteLength),\n etag: storeEtag ? storeEtag.replace(/^(?!W\\/)/, 'W/') : await weakEtag(body),\n };\n}\n\n/** A prerendered page, ready to serve: its body and a validator derived from those exact bytes. */\nexport interface PrerenderedPage {\n /**\n * The document or the flight payload, depending on which {@link PrerenderVariant} was read.\n *\n * Bytes rather than a string, because this is a *cache* entry served verbatim to every request that\n * hits it — held as a string, each of those would pay a fresh UTF-8 encode of the whole page on the\n * way out. Read once, encoded never.\n */\n body: Uint8Array<ArrayBuffer>;\n /**\n * `Content-Length` for {@link body}, in bytes rather than characters. Served explicitly because\n * Hono sets no length for an in-memory body, and a proxy or CDN in front is entitled to make\n * decisions with it — whether gzipping this response is worth the framing, most obviously.\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 something in front re-encoded\n * them, and a strong validator would have to differ per coding — so the 200 and the 304 that\n * revalidates it could disagree, and a cache would treat them as different pages. A weak tag says\n * \"the same representation\", which is what stays true across content codings.\n */\n etag: string;\n}\n"]}
1
+ {"version":3,"file":"prerendered.js","sourceRoot":"","sources":["../../src/server/prerendered.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AASH,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;;;;;;GAMG;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;;;GAGG;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;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,GAAG,GAAG;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;IACjD,OAAO;QACL,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;QAC5B,GAAG,CAAC,GAAG,EAAE,IAAI;YACX,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACrB,qDAAqD;YACrD,IAAI,KAAK,CAAC,IAAI,GAAG,GAAG;gBAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAM,CAAC,CAAC;QACjE,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAA6B;IAC1D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;SACnE,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACtB,OAAO,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAA6B,EAAE,SAAyB;IAC9F,OAAO;QACL,IAAI;QACJ,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;QACtC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC;KAC7E,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Everything about a prerendered page that doesn't need a filesystem: where the build puts it, and what it\n * looks like once read back.\n *\n * Apart from `ssg.ts`, which does the reading and writing through `node:fs`, because a deploy target without a\n * filesystem reads the same layout out of an asset store — and importing it from there would drag `node:fs`\n * into a bundle that has neither.\n */\n\n/**\n * The two representations of a page, prerendered side by side: a hard load wants the HTML document, a soft\n * navigation asks the same URL for a flight payload. Without both, every in-app click would re-render a page\n * that was already built.\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 cannot be\n * prerendered at all, one with a param or a wildcard left in it.\n *\n * Always `/`-separated: the same string addresses a file on a filesystem, which accepts forward slashes on\n * Windows too, and a key in an asset store, where a backslash would 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. A store\n * addressed by key has no `resolve()` to fall back on, so `..` is 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/**\n * A bounded, insertion-ordered cache of prerendered pages, so a site with thousands of them keeps a working set\n * rather than the whole build in memory. Only *hits* are stored — caching misses would let anyone mint entries\n * by requesting paths that don't exist — and the files never change while the server is up.\n */\nexport function createPageCache(max = 128): { get(key: string): PrerenderedPage | undefined; set(key: string, page: PrerenderedPage): void } {\n const pages = new Map<string, PrerenderedPage>();\n return {\n get: (key) => pages.get(key),\n set(key, page) {\n pages.set(key, page);\n // Insertion-ordered, so the first key is the oldest.\n if (pages.size > max) pages.delete(pages.keys().next().value!);\n },\n };\n}\n\n/**\n * A weak `ETag` for a page body — see {@link PrerenderedPage.etag} for why weak. Web Crypto rather than\n * `node:crypto`, so one implementation serves both a Node server and `workerd`.\n */\nexport async function weakEtag(body: Uint8Array<ArrayBuffer>): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', body);\n const base64url = btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=+$/, '');\n return `W/\"${base64url.slice(0, 22)}\"`;\n}\n\n/**\n * Assembles a {@link PrerenderedPage} from a body just read out of the build. `storeEtag` is the validator the\n * store supplied, where it has one: it already describes these exact bytes, so it is weakened rather than\n * replaced by a fresh hash.\n */\nexport async function toPrerenderedPage(body: Uint8Array<ArrayBuffer>, storeEtag?: string | null): Promise<PrerenderedPage> {\n return {\n body,\n contentLength: String(body.byteLength),\n etag: storeEtag ? storeEtag.replace(/^(?!W\\/)/, 'W/') : await weakEtag(body),\n };\n}\n\n/** A prerendered page, ready to serve: its body and a validator derived from those exact bytes. */\nexport interface PrerenderedPage {\n /**\n * The document or the flight payload, depending on which {@link PrerenderVariant} was read. Bytes rather\n * than a string, because this cache entry is served verbatim to every request that hits it — as a string,\n * each would pay a fresh UTF-8 encode of the whole page.\n */\n body: Uint8Array<ArrayBuffer>;\n /**\n * `Content-Length` for {@link body}, in bytes. Served explicitly because Hono sets no length for an\n * in-memory body, and a proxy in front is entitled to make decisions with it.\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 something in front re-encoded them, so a\n * strong validator would differ per coding and a cache would treat the 200 and the 304 that revalidates it\n * as different pages. A weak tag says \"the same representation\", which stays true across codings.\n */\n etag: string;\n}\n"]}
@@ -1,46 +1,39 @@
1
1
  import type { RshonoConfig } from '../config.js';
2
2
  /**
3
- * The framework settings the server bundle needs at request time, fully resolved.
4
- *
5
- * The value is produced once by {@link resolveServerConfig} from `rshono.config.ts`
6
- * and compiled into the server bundle as the `__RSHONO_CONFIG__` literal (see
7
- * `builder/rspack-config.ts`) — there is no runtime env-var interface for these.
8
- *
9
- * Only two fields, because only two things here are decided by the *build*. The per-request
10
- * security controls that used to live alongside them — the CSRF check, the CSP, the body cap — are
11
- * Hono middleware an app registers in `src/server.ts`, where they can be configured per route and
12
- * per environment instead of once per bundle.
3
+ * The framework settings the server bundle needs at request time, fully resolved — produced once by
4
+ * {@link resolveServerConfig} and compiled in as the `__RSHONO_CONFIG__` literal. There is no runtime env-var
5
+ * interface for these, and nothing here is a per-request concern: those are Hono middleware in `src/server.ts`.
13
6
  */
14
7
  export interface ServerConfig {
15
8
  /**
16
- * `true` when the bundle came from `rshono dev`.
17
- *
18
- * Baked in rather than read from `process.env.NODE_ENV` at runtime: it is decided by which command
19
- * produced the bundle, and a deploy target need not have a `process` to read it from.
9
+ * `true` when the bundle came from `rshono dev`. Baked in rather than read from `process.env.NODE_ENV`,
10
+ * because a deploy target need not have a `process`.
20
11
  */
21
12
  isDev: boolean;
22
13
  /** Honour `X-Forwarded-Host` / `-Proto` when resolving the browser-facing URL. Forced on in dev. */
23
14
  trustProxy: boolean;
15
+ /**
16
+ * The output directory this bundle was written to, relative to the project root. Carried into the bundle
17
+ * because `deploy/filesystem.ts` locates the assets and prerendered pages beside it at runtime, and only the
18
+ * compiler knows which directory it used.
19
+ */
20
+ outDir: string;
24
21
  }
25
22
  /**
26
- * The framework's built-in defaults.
27
- *
28
- * `port` and `host` are not config fields at all — they come from `PORT` / `HOST` (or `--port`)
29
- * wherever the address is resolved, `deploy/node/runtime.ts` for a server bundle and `cli/dev.ts`
30
- * for the dev server, and this is what both fall back to.
23
+ * The framework's built-in defaults. `port` and `host` are not config fields — they come from `PORT` / `HOST`
24
+ * or `--port` wherever the address is resolved, and this is what those fall back to.
31
25
  */
32
26
  export declare const SERVER_DEFAULTS: {
33
27
  readonly port: 3000;
34
28
  readonly host: '0.0.0.0';
35
29
  };
36
30
  /**
37
- * Resolve the user's {@link RshonoConfig} into the {@link ServerConfig} baked into the bundle.
38
- *
39
- * `isDev` is a build-time input rather than a config field because it decides one thing the user
40
- * shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy
41
- * is the only way in (it sets the forwarded headers itself and binds to localhost).
31
+ * Resolves the user's config into the {@link ServerConfig} baked into the bundle. `isDev` is a build-time input
32
+ * rather than a config field because it decides one thing the user should not have to: `trustProxy` is forced on
33
+ * under `rshono dev`, where the framework's own localhost proxy is the only way in.
42
34
  */
43
- export declare function resolveServerConfig(config: RshonoConfig, { isDev }: {
35
+ export declare function resolveServerConfig(config: RshonoConfig, { isDev, outDir }: {
44
36
  isDev: boolean;
37
+ outDir: string;
45
38
  }): ServerConfig;
46
39
  //# sourceMappingURL=server-config.d.ts.map
@@ -1 +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;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,EAAE,OAAO,CAAC;IACf,oGAAoG;IACpG,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;aAC1B,IAAI,EAAE,IAAI;aACV,IAAI,EAAE,SAAS;CACP,CAAC;AAEX;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,YAAY,CAKrG"}
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;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,KAAK,EAAE,OAAO,CAAC;IACf,oGAAoG;IACpG,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;aAC1B,IAAI,EAAE,IAAI;aACV,IAAI,EAAE,SAAS;CACP,CAAC;AAEX;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAM7H"}
@@ -1,25 +1,21 @@
1
1
  /**
2
- * The framework's built-in defaults.
3
- *
4
- * `port` and `host` are not config fields at all — they come from `PORT` / `HOST` (or `--port`)
5
- * wherever the address is resolved, `deploy/node/runtime.ts` for a server bundle and `cli/dev.ts`
6
- * for the dev server, and this is what both fall back to.
2
+ * The framework's built-in defaults. `port` and `host` are not config fields — they come from `PORT` / `HOST`
3
+ * or `--port` wherever the address is resolved, and this is what those fall back to.
7
4
  */
8
5
  export const SERVER_DEFAULTS = {
9
6
  port: 3000,
10
7
  host: '0.0.0.0',
11
8
  };
12
9
  /**
13
- * Resolve the user's {@link RshonoConfig} into the {@link ServerConfig} baked into the bundle.
14
- *
15
- * `isDev` is a build-time input rather than a config field because it decides one thing the user
16
- * shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy
17
- * is the only way in (it sets the forwarded headers itself and binds to localhost).
10
+ * Resolves the user's config into the {@link ServerConfig} baked into the bundle. `isDev` is a build-time input
11
+ * rather than a config field because it decides one thing the user should not have to: `trustProxy` is forced on
12
+ * under `rshono dev`, where the framework's own localhost proxy is the only way in.
18
13
  */
19
- export function resolveServerConfig(config, { isDev }) {
14
+ export function resolveServerConfig(config, { isDev, outDir }) {
20
15
  return {
21
16
  isDev,
22
17
  trustProxy: isDev || (config.trustProxy ?? false),
18
+ outDir,
23
19
  };
24
20
  }
25
21
  //# sourceMappingURL=server-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/server/server-config.ts"],"names":[],"mappings":"AA0BA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,SAAS;CACP,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,EAAE,KAAK,EAAsB;IACrF,OAAO;QACL,KAAK;QACL,UAAU,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,KAAK,CAAC;KAClD,CAAC;AACJ,CAAC","sourcesContent":["import type { RshonoConfig } from '../config.js';\n\n/**\n * The framework settings the server bundle needs at request time, fully resolved.\n *\n * The value is produced once by {@link resolveServerConfig} from `rshono.config.ts`\n * and compiled into the server bundle as the `__RSHONO_CONFIG__` literal (see\n * `builder/rspack-config.ts`) — there is no runtime env-var interface for these.\n *\n * Only two fields, because only two things here are decided by the *build*. The per-request\n * security controls that used to live alongside them — the CSRF check, the CSP, the body cap — are\n * Hono middleware an app registers in `src/server.ts`, where they can be configured per route and\n * per environment instead of once per bundle.\n */\nexport interface ServerConfig {\n /**\n * `true` when the bundle came from `rshono dev`.\n *\n * Baked in rather than read from `process.env.NODE_ENV` at runtime: it is decided by which command\n * produced the bundle, and a deploy target need not have a `process` to read it from.\n */\n isDev: boolean;\n /** Honour `X-Forwarded-Host` / `-Proto` when resolving the browser-facing URL. Forced on in dev. */\n trustProxy: boolean;\n}\n\n/**\n * The framework's built-in defaults.\n *\n * `port` and `host` are not config fields at all — they come from `PORT` / `HOST` (or `--port`)\n * wherever the address is resolved, `deploy/node/runtime.ts` for a server bundle and `cli/dev.ts`\n * for the dev server, and this is what both fall back to.\n */\nexport const SERVER_DEFAULTS = {\n port: 3000,\n host: '0.0.0.0',\n} as const;\n\n/**\n * Resolve the user's {@link RshonoConfig} into the {@link ServerConfig} baked into the bundle.\n *\n * `isDev` is a build-time input rather than a config field because it decides one thing the user\n * shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy\n * is the only way in (it sets the forwarded headers itself and binds to localhost).\n */\nexport function resolveServerConfig(config: RshonoConfig, { isDev }: { isDev: boolean }): ServerConfig {\n return {\n isDev,\n trustProxy: isDev || (config.trustProxy ?? false),\n };\n}\n"]}
1
+ {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/server/server-config.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,SAAS;CACP,CAAC;AAEX;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAsC;IAC7G,OAAO;QACL,KAAK;QACL,UAAU,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,KAAK,CAAC;QACjD,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["import type { RshonoConfig } from '../config.js';\n\n/**\n * The framework settings the server bundle needs at request time, fully resolved — produced once by\n * {@link resolveServerConfig} and compiled in as the `__RSHONO_CONFIG__` literal. There is no runtime env-var\n * interface for these, and nothing here is a per-request concern: those are Hono middleware in `src/server.ts`.\n */\nexport interface ServerConfig {\n /**\n * `true` when the bundle came from `rshono dev`. Baked in rather than read from `process.env.NODE_ENV`,\n * because a deploy target need not have a `process`.\n */\n isDev: boolean;\n /** Honour `X-Forwarded-Host` / `-Proto` when resolving the browser-facing URL. Forced on in dev. */\n trustProxy: boolean;\n /**\n * The output directory this bundle was written to, relative to the project root. Carried into the bundle\n * because `deploy/filesystem.ts` locates the assets and prerendered pages beside it at runtime, and only the\n * compiler knows which directory it used.\n */\n outDir: string;\n}\n\n/**\n * The framework's built-in defaults. `port` and `host` are not config fields — they come from `PORT` / `HOST`\n * or `--port` wherever the address is resolved, and this is what those fall back to.\n */\nexport const SERVER_DEFAULTS = {\n port: 3000,\n host: '0.0.0.0',\n} as const;\n\n/**\n * Resolves the user's config into the {@link ServerConfig} baked into the bundle. `isDev` is a build-time input\n * rather than a config field because it decides one thing the user should not have to: `trustProxy` is forced on\n * under `rshono dev`, where the framework's own localhost proxy is the only way in.\n */\nexport function resolveServerConfig(config: RshonoConfig, { isDev, outDir }: { isDev: boolean; outDir: string }): ServerConfig {\n return {\n isDev,\n trustProxy: isDev || (config.trustProxy ?? false),\n outDir,\n };\n}\n"]}
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Registers `handler` for both `SIGINT` and `SIGTERM` — the two signals a process
3
- * manager or `Ctrl-C` uses to ask for a graceful stop. Consolidates the shutdown
4
- * wiring shared by the server bundle and the `start` launcher.
2
+ * Registers `handler` for both `SIGINT` and `SIGTERM` — the two signals a process manager or `Ctrl-C` uses to
3
+ * ask for a graceful stop. Shared by the server bundle and the `start` launcher.
5
4
  */
6
5
  export declare function onShutdown(handler: (signal: NodeJS.Signals) => void): void;
7
6
  //# sourceMappingURL=shutdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/server/shutdown.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,GAAG,IAAI,CAI1E"}
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../src/server/shutdown.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,GAAG,IAAI,CAI1E"}
@@ -1,7 +1,6 @@
1
1
  /**
2
- * Registers `handler` for both `SIGINT` and `SIGTERM` — the two signals a process
3
- * manager or `Ctrl-C` uses to ask for a graceful stop. Consolidates the shutdown
4
- * wiring shared by the server bundle and the `start` launcher.
2
+ * Registers `handler` for both `SIGINT` and `SIGTERM` — the two signals a process manager or `Ctrl-C` uses to
3
+ * ask for a graceful stop. Shared by the server bundle and the `start` launcher.
5
4
  */
6
5
  export function onShutdown(handler) {
7
6
  for (const signal of ['SIGINT', 'SIGTERM']) {
@@ -1 +1 @@
1
- {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/server/shutdown.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAyC;IAClE,KAAK,MAAM,MAAM,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;QACpD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC","sourcesContent":["/**\n * Registers `handler` for both `SIGINT` and `SIGTERM` — the two signals a process\n * manager or `Ctrl-C` uses to ask for a graceful stop. Consolidates the shutdown\n * wiring shared by the server bundle and the `start` launcher.\n */\nexport function onShutdown(handler: (signal: NodeJS.Signals) => void): void {\n for (const signal of ['SIGINT', 'SIGTERM'] as const) {\n process.on(signal, () => handler(signal));\n }\n}\n"]}
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../src/server/shutdown.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAyC;IAClE,KAAK,MAAM,MAAM,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;QACpD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC","sourcesContent":["/**\n * Registers `handler` for both `SIGINT` and `SIGTERM` — the two signals a process manager or `Ctrl-C` uses to\n * ask for a graceful stop. Shared by the server bundle and the `start` launcher.\n */\nexport function onShutdown(handler: (signal: NodeJS.Signals) => void): void {\n for (const signal of ['SIGINT', 'SIGTERM'] as const) {\n process.on(signal, () => handler(signal));\n }\n}\n"]}
@@ -1,11 +1,8 @@
1
1
  import { type Route } from '../router.js';
2
2
  import { type PrerenderedPage, type PrerenderVariant } from './prerendered.js';
3
3
  /**
4
- * Resolve {@link RshonoConfig.siteUrl} to the origin prerendering should render against.
5
- *
6
- * A path is rejected rather than dropped: `'https://example.com/docs'` almost certainly means the
7
- * author expects a base path, and silently serving from the root would be a confusing way to find
8
- * out that isn't supported.
4
+ * Resolves `siteUrl` to the origin prerendering renders against. A path is rejected rather than dropped:
5
+ * `'https://example.com/docs'` means the author expects a base path, which is not supported.
9
6
  */
10
7
  export declare function resolveSiteOrigin(siteUrl: string | undefined): string;
11
8
  export declare function readPrerendered(ssgDir: string, requestPath: string, variant?: PrerenderVariant): Promise<PrerenderedPage | null>;
@@ -13,7 +10,7 @@ interface PrerenderOptions {
13
10
  routes: readonly Route[];
14
11
  fetch: (request: Request) => Response | Promise<Response>;
15
12
  ssgDir: string;
16
- /** {@link RshonoConfig.siteUrl} — the origin absolute URLs in the output are built against. */
13
+ /** The origin absolute URLs in the output are built against — `siteUrl` from `rshono.config.ts`. */
17
14
  siteUrl?: string;
18
15
  }
19
16
  export interface PrerenderResult {
@@ -1 +1 @@
1
- {"version":3,"file":"ssg.d.ts","sourceRoot":"","sources":["../../src/server/ssg.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAS1B;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAUrE;AA4BD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAyB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA8B9I;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAoBD,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA0D/F"}
1
+ {"version":3,"file":"ssg.d.ts","sourceRoot":"","sources":["../../src/server/ssg.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+B,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAQ1B;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAUrE;AA4BD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAyB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA0B9I;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IACzB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,oGAAoG;IACpG,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAiBD,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAyD/F"}
@@ -4,17 +4,13 @@ import { dirname, join, resolve, sep } from 'node:path';
4
4
  import { isPageRoute } from '../router.js';
5
5
  import { createPageCache, prerenderedRelPath, ssgFilePath, toPrerenderedPage, VARIANTS, } from './prerendered.js';
6
6
  /**
7
- * Stand-in origin for a build that didn't declare {@link RshonoConfig.siteUrl}. Deliberately
8
- * obviously-wrong rather than a guess: a page that bakes this into a canonical tag should be easy
9
- * to spot, and the build warns when static routes are prerendered without a real origin.
7
+ * Stand-in origin for a build that declared no `siteUrl`. Obviously wrong rather than a guess, so a page that
8
+ * bakes it into a canonical tag is easy to spot; the build warns as well.
10
9
  */
11
10
  const DEFAULT_SSG_ORIGIN = 'http://localhost';
12
11
  /**
13
- * Resolve {@link RshonoConfig.siteUrl} to the origin prerendering should render against.
14
- *
15
- * A path is rejected rather than dropped: `'https://example.com/docs'` almost certainly means the
16
- * author expects a base path, and silently serving from the root would be a confusing way to find
17
- * out that isn't supported.
12
+ * Resolves `siteUrl` to the origin prerendering renders against. A path is rejected rather than dropped:
13
+ * `'https://example.com/docs'` means the author expects a base path, which is not supported.
18
14
  */
19
15
  export function resolveSiteOrigin(siteUrl) {
20
16
  if (!siteUrl)
@@ -53,9 +49,8 @@ function interpolatePath(pattern, params) {
53
49
  /** Prerendered pages, keyed by the request that produced them (see {@link readPrerendered}). */
54
50
  const pageCache = createPageCache();
55
51
  export async function readPrerendered(ssgDir, requestPath, variant = 'html') {
56
- // Keyed by what the request carried, not by the resolved filename, so a hit costs one Map lookup
57
- // instead of re-deriving the path every time. Safe because only *hits* are cached: an entry
58
- // exists only if this exact key already passed the checks below.
52
+ // Keyed by what the request carried rather than by the resolved filename, so a hit costs one Map lookup. Safe
53
+ // because only *hits* are cached: an entry exists only if this exact key already passed the checks below.
59
54
  const key = `${ssgDir}\0${variant}\0${requestPath}`;
60
55
  const cached = pageCache.get(key);
61
56
  if (cached)
@@ -63,16 +58,13 @@ export async function readPrerendered(ssgDir, requestPath, variant = 'html') {
63
58
  const relPath = prerenderedRelPath(requestPath, variant);
64
59
  if (relPath === null)
65
60
  return null;
66
- // Belt and braces: the shared guard already refused a traversal, and this proves the resolved file
67
- // is under the root whatever else the path contained.
61
+ // Belt and braces over the shared traversal guard: this proves the resolved file is under the root.
68
62
  const root = resolve(ssgDir);
69
63
  const file = resolve(root, relPath);
70
64
  if (!file.startsWith(root + sep))
71
65
  return null;
72
- // No encoding argument: the bytes are what gets served, and decoding them to a string here would
73
- // only mean re-encoding them on every request that hits the cache. Copied out of the Buffer rather
74
- // than kept as one, because `readFile` can hand back a view into Node's shared allocation pool and
75
- // this is retained for the life of the process.
66
+ // No encoding argument: the bytes are what gets served. Copied out of the Buffer rather than kept as one,
67
+ // because `readFile` can hand back a view into Node's shared pool and this is retained for the process.
76
68
  let body;
77
69
  try {
78
70
  body = new Uint8Array(await readFile(file));
@@ -129,9 +121,8 @@ export async function prerenderStaticRoutes(options) {
129
121
  writeFileSync(file, body);
130
122
  };
131
123
  write('html', document.body);
132
- // The soft-navigation representation of the same page. Best-effort: if it doesn't come back
133
- // cleanly the document is still valid on its own, and serving falls back to rendering the
134
- // flight payload per request.
124
+ // The soft-navigation representation of the same page. Best-effort: the document is valid on its own, and
125
+ // serving falls back to rendering the flight payload per request.
135
126
  const flight = await renderVariant(fetch, origin + path, 'flight');
136
127
  if (flight.ok) {
137
128
  write('flight', flight.body);
@@ -1 +1 @@
1
- {"version":3,"file":"ssg.js","sourceRoot":"","sources":["../../src/server/ssg.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve, sep } from 'node:path';\nimport { isPageRoute, type PageRoute, type Route } from '../router.js';\nimport {\n createPageCache,\n prerenderedRelPath,\n ssgFilePath,\n toPrerenderedPage,\n VARIANTS,\n type PrerenderedPage,\n type PrerenderVariant,\n} from './prerendered.js';\n\n/**\n * Stand-in origin for a build that didn't declare {@link RshonoConfig.siteUrl}. Deliberately\n * obviously-wrong rather than a guess: a page that bakes this into a canonical tag should be easy\n * to spot, and the build warns when static routes are prerendered without a real origin.\n */\nconst DEFAULT_SSG_ORIGIN = 'http://localhost';\n\n/**\n * Resolve {@link RshonoConfig.siteUrl} to the origin prerendering should render against.\n *\n * A path is rejected rather than dropped: `'https://example.com/docs'` almost certainly means the\n * author expects a base path, and silently serving from the root would be a confusing way to find\n * out that isn't supported.\n */\nexport function resolveSiteOrigin(siteUrl: string | undefined): string {\n if (!siteUrl) return DEFAULT_SSG_ORIGIN;\n const parsed = URL.parse(siteUrl);\n if (!parsed || (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')) {\n throw new Error(`[rshono] invalid siteUrl ${JSON.stringify(siteUrl)} — use a full origin, e.g. 'https://example.com'.`);\n }\n if (parsed.pathname !== '/' || parsed.search || parsed.hash) {\n throw new Error(`[rshono] siteUrl ${JSON.stringify(siteUrl)} must be a bare origin — a base path is not supported.`);\n }\n return parsed.origin;\n}\n\nfunction interpolatePath(pattern: string, params: Record<string, string>): string {\n return pattern\n .split('/')\n .map((segment) => {\n if (!segment.startsWith(':')) {\n if (segment.includes('*')) {\n throw new Error(`Cannot prerender \"${pattern}\": wildcard segments are not supported by staticPaths.`);\n }\n return segment;\n }\n const name = segment.slice(1);\n if (!/^\\w+$/.test(name)) {\n throw new Error(`Cannot prerender \"${pattern}\": optional/regex params are not supported by staticPaths.`);\n }\n const value = params[name];\n if (value === undefined) {\n throw new Error(`staticPaths for \"${pattern}\" returned a param set without \"${name}\".`);\n }\n return encodeURIComponent(value);\n })\n .join('/');\n}\n\n/** Prerendered pages, keyed by the request that produced them (see {@link readPrerendered}). */\nconst pageCache = createPageCache();\n\nexport async function readPrerendered(ssgDir: string, requestPath: string, variant: PrerenderVariant = 'html'): Promise<PrerenderedPage | null> {\n // Keyed by what the request carried, not by the resolved filename, so a hit costs one Map lookup\n // instead of re-deriving the path every time. Safe because only *hits* are cached: an entry\n // exists only if this exact key already passed the checks below.\n const key = `${ssgDir}\\0${variant}\\0${requestPath}`;\n const cached = pageCache.get(key);\n if (cached) return cached;\n\n const relPath = prerenderedRelPath(requestPath, variant);\n if (relPath === null) return null;\n // Belt and braces: the shared guard already refused a traversal, and this proves the resolved file\n // is under the root whatever else the path contained.\n const root = resolve(ssgDir);\n const file = resolve(root, relPath);\n if (!file.startsWith(root + sep)) return null;\n\n // No encoding argument: the bytes are what gets served, and decoding them to a string here would\n // only mean re-encoding them on every request that hits the cache. Copied out of the Buffer rather\n // than kept as one, because `readFile` can hand back a view into Node's shared allocation pool and\n // this is retained for the life of the process.\n let body: Uint8Array<ArrayBuffer>;\n try {\n body = new Uint8Array(await readFile(file));\n } catch {\n return null;\n }\n\n const page = await toPrerenderedPage(body);\n pageCache.set(key, page);\n return page;\n}\n\ninterface PrerenderOptions {\n routes: readonly Route[];\n fetch: (request: Request) => Response | Promise<Response>;\n ssgDir: string;\n /** {@link RshonoConfig.siteUrl} — the origin absolute URLs in the output are built against. */\n siteUrl?: string;\n}\n\nexport interface PrerenderResult {\n written: string[];\n skipped: string[];\n}\n\n/**\n * One representation of a path, as the app answered for it at build time.\n *\n * Discriminated on `ok` rather than returned as a body-or-status-or-null union: both callers have to\n * tell \"the app rendered this\" from \"it did not\", and only one of them cares *why* — which as three\n * shapes made every read a `'body' in result` check against a value that could also be null.\n */\ntype RenderedVariant = { ok: true; body: string } | { ok: false; reason: string };\n\nasync function renderVariant(fetch: PrerenderOptions['fetch'], url: string, variant: PrerenderVariant): Promise<RenderedVariant> {\n const response = await fetch(new Request(url, { headers: { Accept: VARIANTS[variant].accept } }));\n if (response.status !== 200) return { ok: false, reason: `${response.status}` };\n if (!(response.headers.get('Content-Type') ?? '').includes(VARIANTS[variant].contentType)) {\n return { ok: false, reason: `a non-${VARIANTS[variant].contentType} response` };\n }\n return { ok: true, body: await response.text() };\n}\n\nexport async function prerenderStaticRoutes(options: PrerenderOptions): Promise<PrerenderResult> {\n const { routes, fetch, ssgDir } = options;\n const staticRoutes = routes.filter((r): r is PageRoute => isPageRoute(r) && r.render === 'static');\n const origin = resolveSiteOrigin(options.siteUrl);\n\n if (staticRoutes.length > 0 && !options.siteUrl) {\n console.warn(\n ` ⚠ No siteUrl in rshono.config — prerendered pages are built against ${DEFAULT_SSG_ORIGIN}, so any absolute URL\\n` +\n ` they derive from a page's \\`url\\` prop (canonical tags, og:url, absolute links) will point there.`,\n );\n }\n\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const route of staticRoutes) {\n let paths: string[];\n if (!/[:*]/.test(route.path)) {\n paths = [route.path];\n } else {\n if (!route.staticPaths) {\n console.warn(` ⚠ Static route \"${route.path}\" has params but no staticPaths — will SSR per request.`);\n skipped.push(route.path);\n continue;\n }\n paths = (await route.staticPaths()).map((params) => interpolatePath(route.path, params));\n }\n\n for (const path of paths) {\n const document = await renderVariant(fetch, origin + path, 'html');\n if (!document.ok) {\n console.warn(` ⚠ \"${path}\" rendered ${document.reason} at build time — skipping, will SSR per request.`);\n skipped.push(path);\n continue;\n }\n\n const write = (variant: PrerenderVariant, body: string) => {\n const file = join(ssgDir, ssgFilePath(path, variant)!);\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, body);\n };\n write('html', document.body);\n\n // The soft-navigation representation of the same page. Best-effort: if it doesn't come back\n // cleanly the document is still valid on its own, and serving falls back to rendering the\n // flight payload per request.\n const flight = await renderVariant(fetch, origin + path, 'flight');\n if (flight.ok) {\n write('flight', flight.body);\n } else {\n console.warn(` ⚠ \"${path}\" produced no flight payload — soft navigations to it will render per request.`);\n }\n\n written.push(path);\n }\n }\n\n return { written, skipped };\n}\n"]}
1
+ {"version":3,"file":"ssg.js","sourceRoot":"","sources":["../../src/server/ssg.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdirSync, writeFileSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve, sep } from 'node:path';\nimport { isPageRoute, type PageRoute, type Route } from '../router.js';\nimport {\n createPageCache,\n prerenderedRelPath,\n ssgFilePath,\n toPrerenderedPage,\n VARIANTS,\n type PrerenderedPage,\n type PrerenderVariant,\n} from './prerendered.js';\n\n/**\n * Stand-in origin for a build that declared no `siteUrl`. Obviously wrong rather than a guess, so a page that\n * bakes it into a canonical tag is easy to spot; the build warns as well.\n */\nconst DEFAULT_SSG_ORIGIN = 'http://localhost';\n\n/**\n * Resolves `siteUrl` to the origin prerendering renders against. A path is rejected rather than dropped:\n * `'https://example.com/docs'` means the author expects a base path, which is not supported.\n */\nexport function resolveSiteOrigin(siteUrl: string | undefined): string {\n if (!siteUrl) return DEFAULT_SSG_ORIGIN;\n const parsed = URL.parse(siteUrl);\n if (!parsed || (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')) {\n throw new Error(`[rshono] invalid siteUrl ${JSON.stringify(siteUrl)} — use a full origin, e.g. 'https://example.com'.`);\n }\n if (parsed.pathname !== '/' || parsed.search || parsed.hash) {\n throw new Error(`[rshono] siteUrl ${JSON.stringify(siteUrl)} must be a bare origin — a base path is not supported.`);\n }\n return parsed.origin;\n}\n\nfunction interpolatePath(pattern: string, params: Record<string, string>): string {\n return pattern\n .split('/')\n .map((segment) => {\n if (!segment.startsWith(':')) {\n if (segment.includes('*')) {\n throw new Error(`Cannot prerender \"${pattern}\": wildcard segments are not supported by staticPaths.`);\n }\n return segment;\n }\n const name = segment.slice(1);\n if (!/^\\w+$/.test(name)) {\n throw new Error(`Cannot prerender \"${pattern}\": optional/regex params are not supported by staticPaths.`);\n }\n const value = params[name];\n if (value === undefined) {\n throw new Error(`staticPaths for \"${pattern}\" returned a param set without \"${name}\".`);\n }\n return encodeURIComponent(value);\n })\n .join('/');\n}\n\n/** Prerendered pages, keyed by the request that produced them (see {@link readPrerendered}). */\nconst pageCache = createPageCache();\n\nexport async function readPrerendered(ssgDir: string, requestPath: string, variant: PrerenderVariant = 'html'): Promise<PrerenderedPage | null> {\n // Keyed by what the request carried rather than by the resolved filename, so a hit costs one Map lookup. Safe\n // because only *hits* are cached: an entry exists only if this exact key already passed the checks below.\n const key = `${ssgDir}\\0${variant}\\0${requestPath}`;\n const cached = pageCache.get(key);\n if (cached) return cached;\n\n const relPath = prerenderedRelPath(requestPath, variant);\n if (relPath === null) return null;\n // Belt and braces over the shared traversal guard: this proves the resolved file is under the root.\n const root = resolve(ssgDir);\n const file = resolve(root, relPath);\n if (!file.startsWith(root + sep)) return null;\n\n // No encoding argument: the bytes are what gets served. Copied out of the Buffer rather than kept as one,\n // because `readFile` can hand back a view into Node's shared pool and this is retained for the process.\n let body: Uint8Array<ArrayBuffer>;\n try {\n body = new Uint8Array(await readFile(file));\n } catch {\n return null;\n }\n\n const page = await toPrerenderedPage(body);\n pageCache.set(key, page);\n return page;\n}\n\ninterface PrerenderOptions {\n routes: readonly Route[];\n fetch: (request: Request) => Response | Promise<Response>;\n ssgDir: string;\n /** The origin absolute URLs in the output are built against — `siteUrl` from `rshono.config.ts`. */\n siteUrl?: string;\n}\n\nexport interface PrerenderResult {\n written: string[];\n skipped: string[];\n}\n\n/**\n * One representation of a path, as the app answered for it at build time. Discriminated on `ok` because both\n * callers have to tell \"the app rendered this\" from \"it did not\", and only one cares why.\n */\ntype RenderedVariant = { ok: true; body: string } | { ok: false; reason: string };\n\nasync function renderVariant(fetch: PrerenderOptions['fetch'], url: string, variant: PrerenderVariant): Promise<RenderedVariant> {\n const response = await fetch(new Request(url, { headers: { Accept: VARIANTS[variant].accept } }));\n if (response.status !== 200) return { ok: false, reason: `${response.status}` };\n if (!(response.headers.get('Content-Type') ?? '').includes(VARIANTS[variant].contentType)) {\n return { ok: false, reason: `a non-${VARIANTS[variant].contentType} response` };\n }\n return { ok: true, body: await response.text() };\n}\n\nexport async function prerenderStaticRoutes(options: PrerenderOptions): Promise<PrerenderResult> {\n const { routes, fetch, ssgDir } = options;\n const staticRoutes = routes.filter((r): r is PageRoute => isPageRoute(r) && r.render === 'static');\n const origin = resolveSiteOrigin(options.siteUrl);\n\n if (staticRoutes.length > 0 && !options.siteUrl) {\n console.warn(\n ` ⚠ No siteUrl in rshono.config — prerendered pages are built against ${DEFAULT_SSG_ORIGIN}, so any absolute URL\\n` +\n ` they derive from a page's \\`url\\` prop (canonical tags, og:url, absolute links) will point there.`,\n );\n }\n\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const route of staticRoutes) {\n let paths: string[];\n if (!/[:*]/.test(route.path)) {\n paths = [route.path];\n } else {\n if (!route.staticPaths) {\n console.warn(` ⚠ Static route \"${route.path}\" has params but no staticPaths — will SSR per request.`);\n skipped.push(route.path);\n continue;\n }\n paths = (await route.staticPaths()).map((params) => interpolatePath(route.path, params));\n }\n\n for (const path of paths) {\n const document = await renderVariant(fetch, origin + path, 'html');\n if (!document.ok) {\n console.warn(` ⚠ \"${path}\" rendered ${document.reason} at build time — skipping, will SSR per request.`);\n skipped.push(path);\n continue;\n }\n\n const write = (variant: PrerenderVariant, body: string) => {\n const file = join(ssgDir, ssgFilePath(path, variant)!);\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, body);\n };\n write('html', document.body);\n\n // The soft-navigation representation of the same page. Best-effort: the document is valid on its own, and\n // serving falls back to rendering the flight payload per request.\n const flight = await renderVariant(fetch, origin + path, 'flight');\n if (flight.ok) {\n write('flight', flight.body);\n } else {\n console.warn(` ⚠ \"${path}\" produced no flight payload — soft navigations to it will render per request.`);\n }\n\n written.push(path);\n }\n }\n\n return { written, skipped };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rshono/core",
3
- "version": "1.0.0-rc.11",
3
+ "version": "1.0.0-rc.13",
4
4
  "description": "Minimalist web framework — Hono + Rspack + React Server Components",
5
5
  "author": "Lasse <lasse@lassetange.com> (https://www.lassetange.com)",
6
6
  "license": "ISC",