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

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 (123) hide show
  1. package/README.md +45 -29
  2. package/dist/builder/rspack-config.d.ts +3 -3
  3. package/dist/builder/rspack-config.js +3 -3
  4. package/dist/builder/rspack-config.js.map +1 -1
  5. package/dist/cli/build.d.ts +2 -2
  6. package/dist/cli/build.js.map +1 -1
  7. package/dist/cli/dev.d.ts +2 -2
  8. package/dist/cli/dev.js.map +1 -1
  9. package/dist/cli/index.js +11 -10
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/config.d.ts +4 -17
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/deploy/cloudflare/build.js +1 -1
  15. package/dist/deploy/cloudflare/build.js.map +1 -1
  16. package/dist/deploy/cloudflare/runtime.d.ts.map +1 -1
  17. package/dist/deploy/cloudflare/runtime.js +7 -37
  18. package/dist/deploy/cloudflare/runtime.js.map +1 -1
  19. package/dist/deploy/contract.d.ts +14 -13
  20. package/dist/deploy/contract.d.ts.map +1 -1
  21. package/dist/deploy/contract.js.map +1 -1
  22. package/dist/deploy/filesystem.d.ts +1 -1
  23. package/dist/deploy/filesystem.d.ts.map +1 -1
  24. package/dist/deploy/filesystem.js +1 -3
  25. package/dist/deploy/filesystem.js.map +1 -1
  26. package/dist/deploy/node/runtime.d.ts +6 -2
  27. package/dist/deploy/node/runtime.d.ts.map +1 -1
  28. package/dist/deploy/node/runtime.js +30 -5
  29. package/dist/deploy/node/runtime.js.map +1 -1
  30. package/dist/deploy/presets.d.ts +5 -1
  31. package/dist/deploy/presets.d.ts.map +1 -1
  32. package/dist/deploy/presets.js +15 -28
  33. package/dist/deploy/presets.js.map +1 -1
  34. package/dist/deploy/vercel/runtime.d.ts.map +1 -1
  35. package/dist/deploy/vercel/runtime.js +0 -3
  36. package/dist/deploy/vercel/runtime.js.map +1 -1
  37. package/dist/index.d.ts +4 -9
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +6 -3
  40. package/dist/index.js.map +1 -1
  41. package/dist/router.d.ts +14 -15
  42. package/dist/router.d.ts.map +1 -1
  43. package/dist/router.js +5 -6
  44. package/dist/router.js.map +1 -1
  45. package/dist/runtime/client.d.ts +5 -6
  46. package/dist/runtime/client.d.ts.map +1 -1
  47. package/dist/runtime/client.js +5 -6
  48. package/dist/runtime/client.js.map +1 -1
  49. package/dist/runtime/context.d.ts +36 -40
  50. package/dist/runtime/context.d.ts.map +1 -1
  51. package/dist/runtime/context.js +41 -53
  52. package/dist/runtime/context.js.map +1 -1
  53. package/dist/runtime/entry.client.d.ts +4 -0
  54. package/dist/runtime/entry.client.d.ts.map +1 -1
  55. package/dist/runtime/entry.client.js +161 -147
  56. package/dist/runtime/entry.client.js.map +1 -1
  57. package/dist/runtime/entry.rsc.d.ts.map +1 -1
  58. package/dist/runtime/entry.rsc.js +80 -63
  59. package/dist/runtime/entry.rsc.js.map +1 -1
  60. package/dist/runtime/entry.ssr.d.ts +9 -1
  61. package/dist/runtime/entry.ssr.d.ts.map +1 -1
  62. package/dist/runtime/entry.ssr.js +36 -18
  63. package/dist/runtime/entry.ssr.js.map +1 -1
  64. package/dist/runtime/flight-inject.d.ts +31 -0
  65. package/dist/runtime/flight-inject.d.ts.map +1 -0
  66. package/dist/runtime/flight-inject.js +221 -0
  67. package/dist/runtime/flight-inject.js.map +1 -0
  68. package/dist/runtime/navigation.d.ts +10 -39
  69. package/dist/runtime/navigation.d.ts.map +1 -1
  70. package/dist/runtime/navigation.js +7 -53
  71. package/dist/runtime/navigation.js.map +1 -1
  72. package/dist/runtime/request.d.ts +6 -0
  73. package/dist/runtime/request.d.ts.map +1 -1
  74. package/dist/runtime/request.js +8 -0
  75. package/dist/runtime/request.js.map +1 -1
  76. package/dist/runtime/server.d.ts +2 -2
  77. package/dist/runtime/server.d.ts.map +1 -1
  78. package/dist/runtime/server.js +2 -2
  79. package/dist/runtime/server.js.map +1 -1
  80. package/dist/server/headers.d.ts +9 -9
  81. package/dist/server/headers.js +9 -9
  82. package/dist/server/headers.js.map +1 -1
  83. package/dist/server/load-config.d.ts +2 -2
  84. package/dist/server/load-config.d.ts.map +1 -1
  85. package/dist/server/load-config.js +22 -11
  86. package/dist/server/load-config.js.map +1 -1
  87. package/dist/server/prerendered.d.ts +52 -9
  88. package/dist/server/prerendered.d.ts.map +1 -1
  89. package/dist/server/prerendered.js +57 -0
  90. package/dist/server/prerendered.js.map +1 -1
  91. package/dist/server/server-config.d.ts +11 -18
  92. package/dist/server/server-config.d.ts.map +1 -1
  93. package/dist/server/server-config.js +9 -12
  94. package/dist/server/server-config.js.map +1 -1
  95. package/dist/server/ssg.d.ts +2 -2
  96. package/dist/server/ssg.d.ts.map +1 -1
  97. package/dist/server/ssg.js +11 -23
  98. package/dist/server/ssg.js.map +1 -1
  99. package/package.json +13 -16
  100. package/dist/deploy/bun/runtime.d.ts +0 -11
  101. package/dist/deploy/bun/runtime.d.ts.map +0 -1
  102. package/dist/deploy/bun/runtime.js +0 -22
  103. package/dist/deploy/bun/runtime.js.map +0 -1
  104. package/dist/deploy/deno/runtime.d.ts +0 -11
  105. package/dist/deploy/deno/runtime.d.ts.map +0 -1
  106. package/dist/deploy/deno/runtime.js +0 -16
  107. package/dist/deploy/deno/runtime.js.map +0 -1
  108. package/dist/deploy/listen.d.ts +0 -20
  109. package/dist/deploy/listen.d.ts.map +0 -1
  110. package/dist/deploy/listen.js +0 -24
  111. package/dist/deploy/listen.js.map +0 -1
  112. package/dist/deploy/netlify/build.d.ts +0 -8
  113. package/dist/deploy/netlify/build.d.ts.map +0 -1
  114. package/dist/deploy/netlify/build.js +0 -52
  115. package/dist/deploy/netlify/build.js.map +0 -1
  116. package/dist/deploy/netlify/runtime.d.ts +0 -13
  117. package/dist/deploy/netlify/runtime.d.ts.map +0 -1
  118. package/dist/deploy/netlify/runtime.js +0 -24
  119. package/dist/deploy/netlify/runtime.js.map +0 -1
  120. package/dist/server/compress.d.ts +0 -15
  121. package/dist/server/compress.d.ts.map +0 -1
  122. package/dist/server/compress.js +0 -76
  123. package/dist/server/compress.js.map +0 -1
@@ -1,10 +1,13 @@
1
1
  import { finalizeCloudflareBuild } from './cloudflare/build.js';
2
- import { finalizeNetlifyBuild } from './netlify/build.js';
3
2
  import { finalizeVercelBuild } from './vercel/build.js';
4
3
  /**
5
4
  * Node: a long-lived server process. The generated config is already this shape, so the preset has
6
5
  * nothing to contribute — the platform-specific settings still living in `builder/rspack-config.ts`
7
6
  * (`target: 'node'`, the externals policy, ESM chunk output) are the Node ones by default.
7
+ *
8
+ * Anywhere that runs a Node process runs this build: a VPS, a container, a PaaS. Bun and Deno are
9
+ * expected to as well, through their `node:` compatibility — they had a preset each, and since neither
10
+ * held anything but a default export, running the bundle (`bun dist/server/main.mjs`) replaces it.
8
11
  */
9
12
  export const NODE_PRESET = {
10
13
  name: 'node',
@@ -36,23 +39,11 @@ const CLOUDFLARE_PRESET = {
36
39
  finalize: finalizeCloudflareBuild,
37
40
  };
38
41
  /**
39
- * Bun and Deno: like Node, but the runtime opens the socket from the module's default export. Their
40
- * `node:` compatibility covers everything `server/` uses, so the bundle is Node's only the handoff
41
- * differs, which is precisely the thing an app cannot do for itself.
42
- */
43
- const BUN_PRESET = {
44
- name: 'bun',
45
- runtimeModule: 'deploy/bun/runtime.js',
46
- deployHint: 'run `bun dist/server/main.mjs`',
47
- };
48
- const DENO_PRESET = {
49
- name: 'deno',
50
- runtimeModule: 'deploy/deno/runtime.js',
51
- deployHint: 'run `deno serve -A dist/server/main.mjs`',
52
- };
53
- /**
54
- * Vercel and Netlify: one Node function behind the platform's CDN, which serves the assets and reaches
55
- * the function only for a page. Both `finalize` hooks assemble the layout the platform uploads.
42
+ * Vercel: one Node function behind the platform's CDN, which serves the assets and reaches the function
43
+ * only for a page. `finalize` assembles the Build Output API layout the platform uploadsincluding the
44
+ * `supportsResponseStreaming` flag, without which Vercel buffers the whole response and streamed SSR is
45
+ * silently undone. That flag, and the exact path the bundle has to keep, are the reason this is a preset
46
+ * rather than a snippet in the docs.
56
47
  */
57
48
  const VERCEL_PRESET = {
58
49
  name: 'vercel',
@@ -60,13 +51,12 @@ const VERCEL_PRESET = {
60
51
  deployHint: 'deploy with `vercel deploy --prebuilt`',
61
52
  finalize: finalizeVercelBuild,
62
53
  };
63
- const NETLIFY_PRESET = {
64
- name: 'netlify',
65
- runtimeModule: 'deploy/netlify/runtime.js',
66
- deployHint: 'deploy with `netlify deploy --build=false --dir=.netlify/publish`',
67
- finalize: finalizeNetlifyBuild,
68
- };
69
- /** AWS Lambda behind a Function URL in `RESPONSE_STREAM` mode — the AWS shape that keeps streaming. */
54
+ /**
55
+ * AWS Lambda behind a Function URL in `RESPONSE_STREAM` mode — the AWS shape that keeps streaming.
56
+ *
57
+ * Same reasoning as Vercel: the runtime wraps the app in `awslambda.streamifyResponse`, and the buffered
58
+ * alternative would deploy fine and then hold every page until its last byte rendered.
59
+ */
70
60
  const AWS_LAMBDA_PRESET = {
71
61
  name: 'aws-lambda',
72
62
  runtimeModule: 'deploy/aws-lambda/runtime.js',
@@ -75,10 +65,7 @@ const AWS_LAMBDA_PRESET = {
75
65
  const PRESETS = {
76
66
  node: NODE_PRESET,
77
67
  cloudflare: CLOUDFLARE_PRESET,
78
- bun: BUN_PRESET,
79
- deno: DENO_PRESET,
80
68
  vercel: VERCEL_PRESET,
81
- netlify: NETLIFY_PRESET,
82
69
  'aws-lambda': AWS_LAMBDA_PRESET,
83
70
  };
84
71
  /** Every target `deploy` accepts, for error messages and docs. */
@@ -1 +1 @@
1
- {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/deploy/presets.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RspackOptions } from '@rspack/core';\nimport { finalizeCloudflareBuild } from './cloudflare/build.js';\nimport type { DeployTarget } from './contract.js';\nimport { finalizeNetlifyBuild } from './netlify/build.js';\nimport { finalizeVercelBuild } from './vercel/build.js';\n\n/** What a preset's {@link DeployPreset.finalize} is told about the build it is arranging. */\nexport interface DeployBuildContext {\n /** The project root — where `rshono build` ran, and what a platform config file is written next to. */\n rootDir: string;\n /** `<root>/dist`. */\n distDir: string;\n /** The hashed client bundle, `<root>/dist/static` — served at `/_static`. */\n staticDir: string;\n /** The copy of the app's `public/`, or `null` when it has none. Served at the web root. */\n publicDir: string | null;\n /** Prerendered pages, `<root>/dist/ssg` — empty when the app has no `render: 'static'` routes. */\n ssgDir: string;\n}\n\n/**\n * The build-time half of a deploy target: which runtime module the bundle gets, how the server\n * compiler has to change to produce something the platform can run, and how the output is arranged\n * once it exists.\n *\n * The runtime half is {@link DeployRuntime}, in its own file because it is compiled *into* the app\n * bundle — this side only ever runs in the CLI.\n */\nexport interface DeployPreset {\n readonly name: DeployTarget;\n /**\n * The module `@rshono/deploy` resolves to, as a path relative to the framework's own `dist/`.\n * Slash-separated and split on use, so it stays a valid path on Windows too.\n */\n readonly runtimeModule: string;\n /** How to run what was just built, completing the \"build complete —\" line. */\n readonly deployHint: string;\n /**\n * Extra resolve conditions for the server bundle, most specific first.\n *\n * This is what picks the right build of React and the RSC runtime: both ship one per runtime behind\n * `workerd` / `deno` / `edge-light` / `node` conditions. Omit it to accept whatever the Rspack\n * target implies, which is correct for Node.\n */\n readonly resolveConditions?: readonly string[];\n /** browserslist-style targets for the server bundle's swc pass. Defaults to Node. */\n readonly syntaxTargets?: readonly string[];\n /**\n * Adjusts the generated server Rspack config for this platform — target, externals policy, output\n * shape. Mutates in place, and runs *before* the user's `rspack` hook so that hook keeps the last\n * word.\n */\n configureServer?(config: RspackOptions): void;\n /**\n * Arranges the finished build for the platform: assembles whatever directory layout it expects,\n * emits its config file, and prints how to deploy.\n *\n * Runs last — after both bundles, the `public/` copy and the prerender pass — so everything it\n * needs to move is already on disk.\n */\n finalize?(ctx: DeployBuildContext): Promise<void> | void;\n}\n\n/**\n * Node: a long-lived server process. The generated config is already this shape, so the preset has\n * nothing to contribute — the platform-specific settings still living in `builder/rspack-config.ts`\n * (`target: 'node'`, the externals policy, ESM chunk output) are the Node ones by default.\n */\nexport const NODE_PRESET: DeployPreset = {\n name: 'node',\n runtimeModule: 'deploy/node/runtime.js',\n deployHint: 'run `rshono start`',\n};\n\n/**\n * Cloudflare Workers: the host owns the process, the CDN owns the assets, and there is no filesystem.\n *\n * Every compiler setting here follows from `workerd` not being Node. Dependencies are bundled because\n * nothing resolves `node_modules` at runtime; `node:` and `cloudflare:` imports stay external because\n * the runtime provides them (`nodejs_compat`, which the scaffolded config enables for\n * `AsyncLocalStorage`); and async chunks are inlined because Wrangler's bundler cannot follow the\n * computed specifier Rspack's ESM chunk loader emits — a split bundle would deploy and then fail on\n * the first page render.\n */\nconst CLOUDFLARE_PRESET: DeployPreset = {\n name: 'cloudflare',\n runtimeModule: 'deploy/cloudflare/runtime.js',\n deployHint: 'deploy with `wrangler deploy`',\n resolveConditions: ['workerd'],\n syntaxTargets: ['chrome 120'],\n configureServer(config) {\n config.target = 'webworker';\n config.externalsType = 'module-import';\n config.externals = [/^(?:node|cloudflare):/];\n config.output = { ...config.output, asyncChunks: false };\n },\n finalize: finalizeCloudflareBuild,\n};\n\n/**\n * Bun and Deno: like Node, but the runtime opens the socket from the module's default export. Their\n * `node:` compatibility covers everything `server/` uses, so the bundle is Node's — only the handoff\n * differs, which is precisely the thing an app cannot do for itself.\n */\nconst BUN_PRESET: DeployPreset = {\n name: 'bun',\n runtimeModule: 'deploy/bun/runtime.js',\n deployHint: 'run `bun dist/server/main.mjs`',\n};\n\nconst DENO_PRESET: DeployPreset = {\n name: 'deno',\n runtimeModule: 'deploy/deno/runtime.js',\n deployHint: 'run `deno serve -A dist/server/main.mjs`',\n};\n\n/**\n * Vercel and Netlify: one Node function behind the platform's CDN, which serves the assets and reaches\n * the function only for a page. Both `finalize` hooks assemble the layout the platform uploads.\n */\nconst VERCEL_PRESET: DeployPreset = {\n name: 'vercel',\n runtimeModule: 'deploy/vercel/runtime.js',\n deployHint: 'deploy with `vercel deploy --prebuilt`',\n finalize: finalizeVercelBuild,\n};\n\nconst NETLIFY_PRESET: DeployPreset = {\n name: 'netlify',\n runtimeModule: 'deploy/netlify/runtime.js',\n deployHint: 'deploy with `netlify deploy --build=false --dir=.netlify/publish`',\n finalize: finalizeNetlifyBuild,\n};\n\n/** AWS Lambda behind a Function URL in `RESPONSE_STREAM` mode — the AWS shape that keeps streaming. */\nconst AWS_LAMBDA_PRESET: DeployPreset = {\n name: 'aws-lambda',\n runtimeModule: 'deploy/aws-lambda/runtime.js',\n deployHint: 'zip dist/ with the handler at dist/server/main.mjs',\n};\n\nconst PRESETS: Record<DeployTarget, DeployPreset> = {\n node: NODE_PRESET,\n cloudflare: CLOUDFLARE_PRESET,\n bun: BUN_PRESET,\n deno: DENO_PRESET,\n vercel: VERCEL_PRESET,\n netlify: NETLIFY_PRESET,\n 'aws-lambda': AWS_LAMBDA_PRESET,\n};\n\n/** Every target `deploy` accepts, for error messages and docs. */\nexport const DEPLOY_TARGETS = Object.keys(PRESETS) as DeployTarget[];\n\n/**\n * How to deploy what a given target built, or `null` for a name this rshono does not know — which a\n * `dist/` produced by a newer version can legitimately carry.\n */\nexport function deployHintFor(target: string): string | null {\n return (PRESETS as Record<string, DeployPreset | undefined>)[target]?.deployHint ?? null;\n}\n\n/** Where a deploy target can be named, in precedence order. */\nexport interface DeploySources {\n /** The `--deploy` flag. */\n flag?: string;\n /** The `RSHONO_DEPLOY` env var — for a CI job that deploys the same app to more than one place. */\n env?: string;\n /** {@link RSHonoConfig.deploy} from `rshono.config.ts`. */\n config?: string;\n}\n\n/**\n * Resolves the preset to build with: the flag wins over the environment, which wins over the config\n * file, which wins over the `node` default.\n *\n * Blank values are ignored at every level, so an unset-but-present `RSHONO_DEPLOY=` in a CI\n * environment falls through to the config file instead of failing the build.\n */\nexport function resolveDeployPreset(sources: DeploySources = {}): DeployPreset {\n const target = sources.flag?.trim() || sources.env?.trim() || sources.config?.trim();\n if (!target) return NODE_PRESET;\n\n const preset = (PRESETS as Record<string, DeployPreset | undefined>)[target];\n if (!preset) {\n throw new Error(`[rshono] unknown deploy target ${JSON.stringify(target)} — expected one of: ${DEPLOY_TARGETS.join(', ')}.`);\n }\n return preset;\n}\n"]}
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/deploy/presets.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AA2DxD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,WAAW,GAAiB;IACvC,IAAI,EAAE,MAAM;IACZ,aAAa,EAAE,wBAAwB;IACvC,UAAU,EAAE,oBAAoB;CACjC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,iBAAiB,GAAiB;IACtC,IAAI,EAAE,YAAY;IAClB,aAAa,EAAE,8BAA8B;IAC7C,UAAU,EAAE,+BAA+B;IAC3C,iBAAiB,EAAE,CAAC,SAAS,CAAC;IAC9B,aAAa,EAAE,CAAC,YAAY,CAAC;IAC7B,eAAe,CAAC,MAAM;QACpB,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC;QAC5B,MAAM,CAAC,aAAa,GAAG,eAAe,CAAC;QACvC,MAAM,CAAC,SAAS,GAAG,CAAC,uBAAuB,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,GAAG,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAC3D,CAAC;IACD,QAAQ,EAAE,uBAAuB;CAClC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,aAAa,GAAiB;IAClC,IAAI,EAAE,QAAQ;IACd,aAAa,EAAE,0BAA0B;IACzC,UAAU,EAAE,wCAAwC;IACpD,QAAQ,EAAE,mBAAmB;CAC9B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,iBAAiB,GAAiB;IACtC,IAAI,EAAE,YAAY;IAClB,aAAa,EAAE,8BAA8B;IAC7C,UAAU,EAAE,oDAAoD;CACjE,CAAC;AAEF,MAAM,OAAO,GAAuC;IAClD,IAAI,EAAE,WAAW;IACjB,UAAU,EAAE,iBAAiB;IAC7B,MAAM,EAAE,aAAa;IACrB,YAAY,EAAE,iBAAiB;CAChC,CAAC;AAEF,kEAAkE;AAClE,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAmB,CAAC;AAErE;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAQ,OAAoD,CAAC,MAAM,CAAC,EAAE,UAAU,IAAI,IAAI,CAAC;AAC3F,CAAC;AAYD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAO,GAAkB,EAAE;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IACrF,IAAI,CAAC,MAAM;QAAE,OAAO,WAAW,CAAC;IAEhC,MAAM,MAAM,GAAI,OAAoD,CAAC,MAAM,CAAC,CAAC;IAC7E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,uBAAuB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/H,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import type { RspackOptions } from '@rspack/core';\nimport { finalizeCloudflareBuild } from './cloudflare/build.js';\nimport type { DeployTarget } from './contract.js';\nimport { finalizeVercelBuild } from './vercel/build.js';\n\n/** What a preset's {@link DeployPreset.finalize} is told about the build it is arranging. */\nexport interface DeployBuildContext {\n /** The project root — where `rshono build` ran, and what a platform config file is written next to. */\n rootDir: string;\n /** `<root>/dist`. */\n distDir: string;\n /** The hashed client bundle, `<root>/dist/static` — served at `/_static`. */\n staticDir: string;\n /** The copy of the app's `public/`, or `null` when it has none. Served at the web root. */\n publicDir: string | null;\n /** Prerendered pages, `<root>/dist/ssg` — empty when the app has no `render: 'static'` routes. */\n ssgDir: string;\n}\n\n/**\n * The build-time half of a deploy target: which runtime module the bundle gets, how the server\n * compiler has to change to produce something the platform can run, and how the output is arranged\n * once it exists.\n *\n * The runtime half is {@link DeployRuntime}, in its own file because it is compiled *into* the app\n * bundle — this side only ever runs in the CLI.\n */\nexport interface DeployPreset {\n readonly name: DeployTarget;\n /**\n * The module `@rshono/deploy` resolves to, as a path relative to the framework's own `dist/`.\n * Slash-separated and split on use, so it stays a valid path on Windows too.\n */\n readonly runtimeModule: string;\n /** How to run what was just built, completing the \"build complete —\" line. */\n readonly deployHint: string;\n /**\n * Extra resolve conditions for the server bundle, most specific first.\n *\n * This is what picks the right build of React and the RSC runtime: both ship one per runtime behind\n * `workerd` / `deno` / `edge-light` / `node` conditions. Omit it to accept whatever the Rspack\n * target implies, which is correct for Node.\n */\n readonly resolveConditions?: readonly string[];\n /** browserslist-style targets for the server bundle's swc pass. Defaults to Node. */\n readonly syntaxTargets?: readonly string[];\n /**\n * Adjusts the generated server Rspack config for this platform — target, externals policy, output\n * shape. Mutates in place, and runs *before* the user's `rspack` hook so that hook keeps the last\n * word.\n */\n configureServer?(config: RspackOptions): void;\n /**\n * Arranges the finished build for the platform: assembles whatever directory layout it expects,\n * emits its config file, and prints how to deploy.\n *\n * Runs last — after both bundles, the `public/` copy and the prerender pass — so everything it\n * needs to move is already on disk.\n */\n finalize?(ctx: DeployBuildContext): Promise<void> | void;\n}\n\n/**\n * Node: a long-lived server process. The generated config is already this shape, so the preset has\n * nothing to contribute — the platform-specific settings still living in `builder/rspack-config.ts`\n * (`target: 'node'`, the externals policy, ESM chunk output) are the Node ones by default.\n *\n * Anywhere that runs a Node process runs this build: a VPS, a container, a PaaS. Bun and Deno are\n * expected to as well, through their `node:` compatibility — they had a preset each, and since neither\n * held anything but a default export, running the bundle (`bun dist/server/main.mjs`) replaces it.\n */\nexport const NODE_PRESET: DeployPreset = {\n name: 'node',\n runtimeModule: 'deploy/node/runtime.js',\n deployHint: 'run `rshono start`',\n};\n\n/**\n * Cloudflare Workers: the host owns the process, the CDN owns the assets, and there is no filesystem.\n *\n * Every compiler setting here follows from `workerd` not being Node. Dependencies are bundled because\n * nothing resolves `node_modules` at runtime; `node:` and `cloudflare:` imports stay external because\n * the runtime provides them (`nodejs_compat`, which the scaffolded config enables for\n * `AsyncLocalStorage`); and async chunks are inlined because Wrangler's bundler cannot follow the\n * computed specifier Rspack's ESM chunk loader emits — a split bundle would deploy and then fail on\n * the first page render.\n */\nconst CLOUDFLARE_PRESET: DeployPreset = {\n name: 'cloudflare',\n runtimeModule: 'deploy/cloudflare/runtime.js',\n deployHint: 'deploy with `wrangler deploy`',\n resolveConditions: ['workerd'],\n syntaxTargets: ['chrome 120'],\n configureServer(config) {\n config.target = 'webworker';\n config.externalsType = 'module-import';\n config.externals = [/^(?:node|cloudflare):/];\n config.output = { ...config.output, asyncChunks: false };\n },\n finalize: finalizeCloudflareBuild,\n};\n\n/**\n * Vercel: one Node function behind the platform's CDN, which serves the assets and reaches the function\n * only for a page. `finalize` assembles the Build Output API layout the platform uploads — including the\n * `supportsResponseStreaming` flag, without which Vercel buffers the whole response and streamed SSR is\n * silently undone. That flag, and the exact path the bundle has to keep, are the reason this is a preset\n * rather than a snippet in the docs.\n */\nconst VERCEL_PRESET: DeployPreset = {\n name: 'vercel',\n runtimeModule: 'deploy/vercel/runtime.js',\n deployHint: 'deploy with `vercel deploy --prebuilt`',\n finalize: finalizeVercelBuild,\n};\n\n/**\n * AWS Lambda behind a Function URL in `RESPONSE_STREAM` mode — the AWS shape that keeps streaming.\n *\n * Same reasoning as Vercel: the runtime wraps the app in `awslambda.streamifyResponse`, and the buffered\n * alternative would deploy fine and then hold every page until its last byte rendered.\n */\nconst AWS_LAMBDA_PRESET: DeployPreset = {\n name: 'aws-lambda',\n runtimeModule: 'deploy/aws-lambda/runtime.js',\n deployHint: 'zip dist/ with the handler at dist/server/main.mjs',\n};\n\nconst PRESETS: Record<DeployTarget, DeployPreset> = {\n node: NODE_PRESET,\n cloudflare: CLOUDFLARE_PRESET,\n vercel: VERCEL_PRESET,\n 'aws-lambda': AWS_LAMBDA_PRESET,\n};\n\n/** Every target `deploy` accepts, for error messages and docs. */\nexport const DEPLOY_TARGETS = Object.keys(PRESETS) as DeployTarget[];\n\n/**\n * How to deploy what a given target built, or `null` for a name this rshono does not know — which a\n * `dist/` produced by a newer version can legitimately carry.\n */\nexport function deployHintFor(target: string): string | null {\n return (PRESETS as Record<string, DeployPreset | undefined>)[target]?.deployHint ?? null;\n}\n\n/** Where a deploy target can be named, in precedence order. */\nexport interface DeploySources {\n /** The `--deploy` flag. */\n flag?: string;\n /** The `RSHONO_DEPLOY` env var — for a CI job that deploys the same app to more than one place. */\n env?: string;\n /** {@link RshonoConfig.deploy} from `rshono.config.ts`. */\n config?: string;\n}\n\n/**\n * Resolves the preset to build with: the flag wins over the environment, which wins over the config\n * file, which wins over the `node` default.\n *\n * Blank values are ignored at every level, so an unset-but-present `RSHONO_DEPLOY=` in a CI\n * environment falls through to the config file instead of failing the build.\n */\nexport function resolveDeployPreset(sources: DeploySources = {}): DeployPreset {\n const target = sources.flag?.trim() || sources.env?.trim() || sources.config?.trim();\n if (!target) return NODE_PRESET;\n\n const preset = (PRESETS as Record<string, DeployPreset | undefined>)[target];\n if (!preset) {\n throw new Error(`[rshono] unknown deploy target ${JSON.stringify(target)} — expected one of: ${DEPLOY_TARGETS.join(', ')}.`);\n }\n return preset;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,EAAE,aAcrB,CAAC"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,EAAE,aAUrB,CAAC"}
@@ -19,8 +19,5 @@ export const runtime = {
19
19
  serveApp(app) {
20
20
  return handle(app);
21
21
  },
22
- // Vercel compresses at the edge. Its Node runtime does support streaming, so the framework's own
23
- // streamed SSR still reaches the browser progressively.
24
- compress: null,
25
22
  };
26
23
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,GAAG,iBAAiB;IAEpB,iBAAiB;QACf,gEAAgE;IAClE,CAAC;IAED,QAAQ,CAAC,GAAS;QAChB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,iGAAiG;IACjG,wDAAwD;IACxD,QAAQ,EAAE,IAAI;CACf,CAAC","sourcesContent":["import type { Hono } from 'hono';\nimport { handle } from 'hono/vercel';\nimport type { DeployRuntime } from '../contract.js';\nimport { fileSystemRuntime } from '../filesystem.js';\n\n/**\n * Vercel, as a single Node function fed by the platform's own router.\n *\n * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler\n * ahead of the function — so the CDN answers them and the function is never invoked for an asset,\n * which is why mounting them here would only be dead weight.\n *\n * Prerendered pages are *not* static output: one URL answers with a document or a flight payload\n * depending on `Accept`, and a path-keyed CDN cannot choose. They ship inside the function instead and\n * are read from its read-only disk, exactly as on a server.\n */\nexport const runtime: DeployRuntime = {\n ...fileSystemRuntime,\n\n mountStaticAssets(): void {\n // Served from `.vercel/output/static` before the function runs.\n },\n\n serveApp(app: Hono): unknown {\n return handle(app);\n },\n\n // Vercel compresses at the edge. Its Node runtime does support streaming, so the framework's own\n // streamed SSR still reaches the browser progressively.\n compress: null,\n};\n"]}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,GAAG,iBAAiB;IAEpB,iBAAiB;QACf,gEAAgE;IAClE,CAAC;IAED,QAAQ,CAAC,GAAS;QAChB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;CACF,CAAC","sourcesContent":["import type { Hono } from 'hono';\nimport { handle } from 'hono/vercel';\nimport type { DeployRuntime } from '../contract.js';\nimport { fileSystemRuntime } from '../filesystem.js';\n\n/**\n * Vercel, as a single Node function fed by the platform's own router.\n *\n * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler\n * ahead of the function — so the CDN answers them and the function is never invoked for an asset,\n * which is why mounting them here would only be dead weight.\n *\n * Prerendered pages are *not* static output: one URL answers with a document or a flight payload\n * depending on `Accept`, and a path-keyed CDN cannot choose. They ship inside the function instead and\n * are read from its read-only disk, exactly as on a server.\n */\nexport const runtime: DeployRuntime = {\n ...fileSystemRuntime,\n\n mountStaticAssets(): void {\n // Served from `.vercel/output/static` before the function runs.\n },\n\n serveApp(app: Hono): unknown {\n return handle(app);\n },\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -5,19 +5,14 @@
5
5
  *
6
6
  * The two companion entry points are runtime-only:
7
7
  * - `@rshono/core/server` — {@link https://hono.dev | Hono} request context inside
8
- * server components and actions (`getContext`, `redirect`, `notFound`), plus
8
+ * server components and actions (`getRequestContext`, `redirect`, `notFound`), plus
9
9
  * `onServerError` for reporting the errors the framework catches.
10
10
  * - `@rshono/core/client` — hooks and components for `'use client'` modules
11
- * (`useNavigation`, `Boundary`, `ErrorBoundary`, `NavigationProgress`).
11
+ * (`useNavigation`, `Boundary`, `ErrorBoundary`).
12
12
  *
13
13
  * @packageDocumentation
14
14
  */
15
- export { defineRoutes, isPageRoute, type EndpointRoute, type EndpointServerModule, type ErrorInfo, type ErrorPageProps, type FallbackPage, type HTTPMethod, type PageComponent, type PageProps, type PageRoute, type PathParams, type Route, type RouteConfig, } from './router.js';
16
- export { defineConfig, type RSHonoConfig, type RspackHookContext } from './config.js';
15
+ export { defineRoutes, type EndpointRoute, type EndpointServerModule, type ErrorPageInfo, type ErrorPageProps, type FallbackPage, type HTTPMethod, type PageComponent, type PageProps, type PageRoute, type PathParams, type Route, type RouteConfig, } from './router.js';
16
+ export { defineConfig, type RshonoConfig, type RspackHookContext } from './config.js';
17
17
  export type { DeployTarget } from './deploy/contract.js';
18
- /**
19
- * Re-exported from Hono for convenience, so an endpoint module can type its
20
- * `handler` without depending on `hono` directly.
21
- */
22
- export type { Context, Handler } from 'hono';
23
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,YAAY,EACZ,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEtF,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;;GAGG;AACH,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,WAAW,GACjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEtF,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -5,13 +5,16 @@
5
5
  *
6
6
  * The two companion entry points are runtime-only:
7
7
  * - `@rshono/core/server` — {@link https://hono.dev | Hono} request context inside
8
- * server components and actions (`getContext`, `redirect`, `notFound`), plus
8
+ * server components and actions (`getRequestContext`, `redirect`, `notFound`), plus
9
9
  * `onServerError` for reporting the errors the framework catches.
10
10
  * - `@rshono/core/client` — hooks and components for `'use client'` modules
11
- * (`useNavigation`, `Boundary`, `ErrorBoundary`, `NavigationProgress`).
11
+ * (`useNavigation`, `Boundary`, `ErrorBoundary`).
12
12
  *
13
13
  * @packageDocumentation
14
14
  */
15
- export { defineRoutes, isPageRoute, } from './router.js';
15
+ export { defineRoutes, } from './router.js';
16
16
  export { defineConfig } from './config.js';
17
+ // Hono's own `Context` and `Handler` used to be re-exported from here "for convenience". They are
18
+ // Hono's types, `hono` is a peer dependency every app already has, and importing them from two places
19
+ // only raised the question of which one is right — so an endpoint module imports them from `hono`.
17
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,YAAY,EACZ,WAAW,GAaZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAA6C,MAAM,aAAa,CAAC","sourcesContent":["/**\n * `@rshono/core` — the build-time surface: route and config declaration plus the types\n * your pages and endpoints are written against. Everything here is safe to\n * import from server code; none of it pulls in runtime machinery.\n *\n * The two companion entry points are runtime-only:\n * - `@rshono/core/server` — {@link https://hono.dev | Hono} request context inside\n * server components and actions (`getContext`, `redirect`, `notFound`), plus\n * `onServerError` for reporting the errors the framework catches.\n * - `@rshono/core/client` — hooks and components for `'use client'` modules\n * (`useNavigation`, `Boundary`, `ErrorBoundary`, `NavigationProgress`).\n *\n * @packageDocumentation\n */\n\nexport {\n defineRoutes,\n isPageRoute,\n type EndpointRoute,\n type EndpointServerModule,\n type ErrorInfo,\n type ErrorPageProps,\n type FallbackPage,\n type HTTPMethod,\n type PageComponent,\n type PageProps,\n type PageRoute,\n type PathParams,\n type Route,\n type RouteConfig,\n} from './router.js';\n\nexport { defineConfig, type RSHonoConfig, type RspackHookContext } from './config.js';\n\nexport type { DeployTarget } from './deploy/contract.js';\n\n/**\n * Re-exported from Hono for convenience, so an endpoint module can type its\n * `handler` without depending on `hono` directly.\n */\nexport type { Context, Handler } from 'hono';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,YAAY,GAab,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAA6C,MAAM,aAAa,CAAC;AAItF,kGAAkG;AAClG,sGAAsG;AACtG,mGAAmG","sourcesContent":["/**\n * `@rshono/core` — the build-time surface: route and config declaration plus the types\n * your pages and endpoints are written against. Everything here is safe to\n * import from server code; none of it pulls in runtime machinery.\n *\n * The two companion entry points are runtime-only:\n * - `@rshono/core/server` — {@link https://hono.dev | Hono} request context inside\n * server components and actions (`getRequestContext`, `redirect`, `notFound`), plus\n * `onServerError` for reporting the errors the framework catches.\n * - `@rshono/core/client` — hooks and components for `'use client'` modules\n * (`useNavigation`, `Boundary`, `ErrorBoundary`).\n *\n * @packageDocumentation\n */\n\nexport {\n defineRoutes,\n type EndpointRoute,\n type EndpointServerModule,\n type ErrorPageInfo,\n type ErrorPageProps,\n type FallbackPage,\n type HTTPMethod,\n type PageComponent,\n type PageProps,\n type PageRoute,\n type PathParams,\n type Route,\n type RouteConfig,\n} from './router.js';\n\nexport { defineConfig, type RshonoConfig, type RspackHookContext } from './config.js';\n\nexport type { DeployTarget } from './deploy/contract.js';\n\n// Hono's own `Context` and `Handler` used to be re-exported from here \"for convenience\". They are\n// Hono's types, `hono` is a peer dependency every app already has, and importing them from two places\n// only raised the question of which one is right so an endpoint module imports them from `hono`.\n"]}
package/dist/router.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Env, Handler } from 'hono';
2
2
  import type { ParamKeys, ParamKeyToRecord } from 'hono/types';
3
3
  import type { ReactNode } from 'react';
4
- import type { Ctx } from './runtime/context.js';
4
+ import type { RequestContext } from './runtime/context.js';
5
5
  type Simplify<T> = {
6
6
  [K in keyof T]: T[K];
7
7
  } & {};
@@ -34,8 +34,8 @@ export type PathParams<P extends string> = ParamKeys<P> extends never ? Record<s
34
34
  * the server/client line is a copy-paste.
35
35
  *
36
36
  * @typeParam Path - The literal path this page is mounted at, e.g. `'/profile/:id'`.
37
- * @typeParam E - The app's Hono {@link Env}, to type {@link Ctx.var} and
38
- * {@link Ctx.env} on {@link PageProps.ctx}.
37
+ * @typeParam E - The app's Hono {@link Env}, to type {@link RequestContext.var} and
38
+ * {@link RequestContext.env} on {@link PageProps.ctx}.
39
39
  *
40
40
  * @example
41
41
  * ```tsx
@@ -68,7 +68,7 @@ export interface PageProps<Path extends string = string, E extends Env = Env> {
68
68
  /** Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. */
69
69
  params: string extends Path ? Record<string, string> : PathParams<Path>;
70
70
  /**
71
- * The request context — the very object `getContext()` returns, handed to the
71
+ * The request context — the very object `getRequestContext()` returns, handed to the
72
72
  * page so cookies, headers, env and middleware variables are reachable without
73
73
  * an import.
74
74
  *
@@ -101,7 +101,7 @@ export interface PageProps<Path extends string = string, E extends Env = Env> {
101
101
  * }
102
102
  * ```
103
103
  */
104
- ctx: Ctx<E>;
104
+ ctx: RequestContext<E>;
105
105
  }
106
106
  /**
107
107
  * A page: a React **server component** that renders the entire document
@@ -122,7 +122,7 @@ export type PageComponent<P = any> = (props: P) => ReactNode | Promise<ReactNode
122
122
  * @example
123
123
  * ```ts
124
124
  * // src/health.ts
125
- * import type { Handler } from '@rshono/core';
125
+ * import type { Handler } from 'hono';
126
126
  *
127
127
  * export const handler: Handler = (c) => c.json({ ok: true });
128
128
  * ```
@@ -211,12 +211,11 @@ export type Route = PageRoute | EndpointRoute;
211
211
  * Type guard narrowing a {@link Route} to a {@link PageRoute}. Because `type` is
212
212
  * optional on page routes, anything not explicitly `'endpoint'` is a page.
213
213
  *
214
- * @example
215
- * ```ts
216
- * for (const route of routes) {
217
- * if (isPageRoute(route)) console.log(route.render ?? 'dynamic');
218
- * }
219
- * ```
214
+ * Framework internal — deliberately absent from `index.ts`, so it is not part of the
215
+ * `@rshono/core` surface. The request renderer and the builder use it to split the
216
+ * route table; an app declares its routes rather than walking them.
217
+ *
218
+ * @internal
220
219
  */
221
220
  export declare function isPageRoute(route: Route): route is PageRoute;
222
221
  /**
@@ -235,7 +234,7 @@ export interface FallbackPage {
235
234
  * message is a generic `'Internal Server Error'` and there is no `stack`. In dev
236
235
  * you get the real message plus the stack.
237
236
  */
238
- export interface ErrorInfo {
237
+ export interface ErrorPageInfo {
239
238
  /** The thrown error's message in dev; `'Internal Server Error'` in production. */
240
239
  message: string;
241
240
  /** The stack trace. Present in dev only. */
@@ -243,7 +242,7 @@ export interface ErrorInfo {
243
242
  }
244
243
  /**
245
244
  * Props for the `error` page declared in {@link RouteConfig.error} — the usual
246
- * {@link PageProps} plus the redaction-aware {@link ErrorInfo}.
245
+ * {@link PageProps} plus the redaction-aware {@link ErrorPageInfo}.
247
246
  *
248
247
  * @typeParam E - The app's Hono {@link Env}, forwarded to {@link PageProps.ctx}.
249
248
  *
@@ -257,7 +256,7 @@ export interface ErrorInfo {
257
256
  * ```
258
257
  */
259
258
  export type ErrorPageProps<E extends Env = Env> = PageProps<string, E> & {
260
- error: ErrorInfo;
259
+ error: ErrorPageInfo;
261
260
  };
262
261
  /**
263
262
  * The object form accepted by {@link defineRoutes}: the route table plus the two
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
package/dist/router.js CHANGED
@@ -2,12 +2,11 @@
2
2
  * Type guard narrowing a {@link Route} to a {@link PageRoute}. Because `type` is
3
3
  * optional on page routes, anything not explicitly `'endpoint'` is a page.
4
4
  *
5
- * @example
6
- * ```ts
7
- * for (const route of routes) {
8
- * if (isPageRoute(route)) console.log(route.render ?? 'dynamic');
9
- * }
10
- * ```
5
+ * Framework internal — deliberately absent from `index.ts`, so it is not part of the
6
+ * `@rshono/core` surface. The request renderer and the builder use it to split the
7
+ * route table; an app declares its routes rather than walking them.
8
+ *
9
+ * @internal
11
10
  */
12
11
  export function isPageRoute(route) {
13
12
  return route.type !== 'endpoint';
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AA0NA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,KAAY;IACtC,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAwHD,MAAM,UAAU,YAAY,CAAC,KAAqC;IAChE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAE,KAAqB,CAAC;AAC3E,CAAC","sourcesContent":["import type { Env, Handler } from 'hono';\nimport type { ParamKeys, ParamKeyToRecord } from 'hono/types';\nimport type { ReactNode } from 'react';\n// Type-only, so this stays a build-time module: the import is erased and none of `context.ts`'s\n// runtime machinery (AsyncLocalStorage, hono/cookie) is pulled in by importing `@rshono/core`.\nimport type { Ctx } from './runtime/context.js';\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\ntype UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\n\n/**\n * The `params` record implied by a route path pattern — one required `string` key\n * per `:param` segment, `Record<string, never>` for a path with no params.\n *\n * Paths use Hono's syntax, so `:id`, `:id{[0-9]+}` and `*` all work. You rarely\n * name this type directly; {@link PageProps} applies it for you.\n *\n * @typeParam P - The literal route path, e.g. `'/users/:id/posts/:postId'`.\n *\n * @example\n * ```ts\n * type P = PathParams<'/users/:id/posts/:postId'>; // { id: string; postId: string }\n * ```\n */\nexport type PathParams<P extends string> =\n ParamKeys<P> extends never ? Record<string, never> : Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P>>>>;\n\n/**\n * Props every page component receives. Pass the route's path as the type\n * argument to get `params` typed key-by-key; without it `params` falls back to\n * an open `Record<string, string>`.\n *\n * `defineRoutes` checks each page's props against `PageProps<path>` at compile\n * time, so a mismatched path literal is a type error at the route definition.\n *\n * The location props (`url` and `params`) mirror what a `'use client'` component\n * gets from `useNavigation()` — same names, same types — so moving a read across\n * the server/client line is a copy-paste.\n *\n * @typeParam Path - The literal path this page is mounted at, e.g. `'/profile/:id'`.\n * @typeParam E - The app's Hono {@link Env}, to type {@link Ctx.var} and\n * {@link Ctx.env} on {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { PageProps } from '@rshono/core';\n *\n * export default async function Profile({ params, url }: PageProps<'/profile/:id'>) {\n * const user = await db.getUser(params.id); // params.id is string\n * const tab = url.searchParams.get('tab') ?? 'overview';\n * return <Layout>{user.name} — {tab}</Layout>;\n * }\n * ```\n */\nexport interface PageProps<Path extends string = string, E extends Env = Env> {\n /**\n * The absolute browser-facing request {@link URL}, proxy-header aware\n * (`X-Forwarded-Host` / `-Proto`). Read `url.pathname`, `url.searchParams` and\n * the rest off it.\n *\n * A fresh instance per request that nothing else holds, so mutating it is local\n * to the page — but note it is *not* serializable, so a `'use client'` component\n * has to be handed `url.href` rather than `url`.\n *\n * On a prerendered page it is the build-time URL: a `render: 'static'` route is\n * rendered once, against `siteUrl` and with no query string, and that one file\n * then answers every request whatever its own query. So `url.searchParams` is\n * always empty there — read the query from `useNavigation().url` in a\n * `'use client'` component instead, or mark the route `render: 'dynamic'`.\n */\n url: URL;\n /** Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. */\n params: string extends Path ? Record<string, string> : PathParams<Path>;\n /**\n * The request context — the very object `getContext()` returns, handed to the\n * page so cookies, headers, env and middleware variables are reachable without\n * an import.\n *\n * Server-only, and never serialized: React renders a server component and puts\n * its *output* on the wire, not its props. It is also deliberately a\n * non-enumerable property, which has three consequences worth knowing:\n *\n * - It **cannot be handed to a `'use client'` component** — it wraps the live\n * request and response, which do not exist in the browser. Passing it\n * explicitly (`<Counter ctx={ctx} />`) fails the render with React's *\"Only\n * plain objects … can be passed to Client Components\"*. Read what you need on\n * the server and pass plain values down.\n * - Spreading the page's props instead (`<Counter {...props} />`) drops `ctx`\n * silently rather than failing, since the spread copies enumerables only.\n * (That spread still fails, mind — on `url`, which is enumerable and just as\n * unserializable. Pass the values you need.)\n * - `Object.keys(props)`, `JSON.stringify(props)` and friends don't see it.\n *\n * Reading it on a `render: 'static'` route throws: a prerendered page has no\n * per-request context at build time. Mark the route `render: 'dynamic'` (or use\n * the `url` / `params` props, which are available either way — with the\n * build-time caveats noted on `url`).\n *\n * @example\n * ```tsx\n * export default function Dashboard({ ctx }: PageProps) {\n * const session = ctx.cookies.get('session');\n * if (!session) redirect('/login');\n * return <Layout>Signed in as {session}</Layout>;\n * }\n * ```\n */\n ctx: Ctx<E>;\n}\n\n/**\n * A page: a React **server component** that renders the entire document\n * (`<html>…</html>`), usually via a shared layout. It may be `async` and await\n * data directly.\n *\n * Each page module must default-export exactly one of these. Interactive parts\n * belong in `'use client'` components the page imports — only those ship JS.\n *\n * @typeParam P - The component's props; for a page these are {@link PageProps}.\n */\nexport type PageComponent<P = any> = (props: P) => ReactNode | Promise<ReactNode>;\n\n/**\n * The shape an `{ type: 'endpoint' }` route's server module must have: a single\n * named `handler` export. The module only ever loads on the server, so it is\n * safe to import a database client or read secrets from it.\n *\n * @example\n * ```ts\n * // src/health.ts\n * import type { Handler } from '@rshono/core';\n *\n * export const handler: Handler = (c) => c.json({ ok: true });\n * ```\n */\nexport interface EndpointServerModule {\n /** A Hono {@link Handler} handling every request matched by the route. */\n handler: Handler;\n}\n\n/**\n * A page route — a path rendered by a server component. This is the default\n * route kind, so `type` can be omitted.\n *\n * @example\n * ```ts\n * { path: '/profile/:id', component: () => import('./components/profile') }\n * ```\n */\nexport interface PageRoute {\n /** Discriminates a page from an endpoint; optional because `'page'` is the default. */\n type?: 'page';\n /** Hono-style path pattern, e.g. `/`, `/profile/:id`, `/files/*`. */\n path: string;\n /**\n * Dynamic import of the page module, whose default export is the\n * {@link PageComponent}.\n *\n * Write it inline as shown — the framework detects that exact\n * `() => import('…')` form and injects Rspack's `'use server-entry'`\n * directive into the module for you (that directive is what attaches the\n * page's client JS/CSS, giving per-page code splitting). If you wire the\n * component up any other way — a variable, a barrel re-export, a computed\n * specifier — add `'use server-entry'` as the first line of the page module\n * yourself; the framework throws a descriptive error when neither happened.\n */\n component: () => Promise<{ default: PageComponent }>;\n /** `'static'` prerenders the route at build time; `'dynamic'` (the default) renders per request. */\n render?: 'static' | 'dynamic';\n /**\n * For a `render: 'static'` route with params: the param sets to prerender, one\n * HTML file each. Runs at build time only, on the server, so it may hit a\n * database or read the filesystem.\n *\n * A parameterised static route without `staticPaths` falls back to rendering\n * per request (with a build warning). Wildcard (`*`), optional and regex\n * params can't be prerendered.\n *\n * @example\n * ```ts\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => (await db.docs.all()).map((d) => ({ slug: d.slug })),\n * }\n * ```\n */\n staticPaths?: () => Array<Record<string, string>> | Promise<Array<Record<string, string>>>;\n}\n\n/**\n * An endpoint route — a path served by a raw Hono handler instead of a React\n * component. Use it for JSON APIs, webhooks, redirects, feeds, or anything that\n * isn't an HTML page.\n *\n * @example\n * ```ts\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') }\n * ```\n */\nexport interface EndpointRoute {\n /** Marks this route as an endpoint rather than a page. Required. */\n type: 'endpoint';\n /** Hono-style path pattern, e.g. `/api/health`, `/api/users/:id`. */\n path: string;\n /** HTTP method to match. Defaults to `'all'` — every method. */\n method?: HTTPMethod;\n /** Dynamic import of the {@link EndpointServerModule} exporting `handler`. */\n server: () => Promise<EndpointServerModule>;\n}\n\n/** HTTP methods an {@link EndpointRoute} can match. `'all'` matches every method. */\nexport type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'all';\n\n/** Any entry in the `routes` array: a {@link PageRoute} or an {@link EndpointRoute}. */\nexport type Route = PageRoute | EndpointRoute;\n\n/**\n * Type guard narrowing a {@link Route} to a {@link PageRoute}. Because `type` is\n * optional on page routes, anything not explicitly `'endpoint'` is a page.\n *\n * @example\n * ```ts\n * for (const route of routes) {\n * if (isPageRoute(route)) console.log(route.render ?? 'dynamic');\n * }\n * ```\n */\nexport function isPageRoute(route: Route): route is PageRoute {\n return route.type !== 'endpoint';\n}\n\n/**\n * A page the framework falls back to rather than routes to — `notFound` and\n * `error` in {@link RouteConfig}. Same contract as a {@link PageRoute}\n * `component`, without a path of its own.\n */\nexport interface FallbackPage {\n /** Dynamic import of the page module; its default export is the {@link PageComponent}. */\n component: () => Promise<{ default: PageComponent }>;\n}\n\n/**\n * The error detail handed to the `error` page. Redacted in production: the\n * message is a generic `'Internal Server Error'` and there is no `stack`. In dev\n * you get the real message plus the stack.\n */\nexport interface ErrorInfo {\n /** The thrown error's message in dev; `'Internal Server Error'` in production. */\n message: string;\n /** The stack trace. Present in dev only. */\n stack?: string;\n}\n\n/**\n * Props for the `error` page declared in {@link RouteConfig.error} — the usual\n * {@link PageProps} plus the redaction-aware {@link ErrorInfo}.\n *\n * @typeParam E - The app's Hono {@link Env}, forwarded to {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { ErrorPageProps } from '@rshono/core';\n *\n * export default function ServerError({ error }: ErrorPageProps) {\n * return <html><body><h1>Something went wrong</h1><p>{error.message}</p></body></html>;\n * }\n * ```\n */\nexport type ErrorPageProps<E extends Env = Env> = PageProps<string, E> & { error: ErrorInfo };\n\n/**\n * The object form accepted by {@link defineRoutes}: the route table plus the two\n * optional framework-owned pages.\n *\n * @typeParam TRoutes - Inferred tuple of route literals, which is what makes the\n * per-route `path` → props check possible.\n */\nexport interface RouteConfig<TRoutes extends readonly Route[] = readonly Route[]> {\n /** Every page and endpoint in the app, matched in order. */\n routes: TRoutes;\n /** Page rendered with a 404 status for unmatched paths and for `notFound()` calls. */\n notFound?: FallbackPage;\n /** Page rendered with a 500 status when a request throws. Receives {@link ErrorPageProps}. */\n error?: FallbackPage;\n}\n\n// `PageProps<P, any>`, not `PageProps<P>`: this check is about the *path* matching the page's\n// `params`, and pinning the Env to the default would additionally demand that a page declaring its\n// own (`PageProps<'/x', MyEnv>`, to type `ctx.var`) accept a `Ctx<Env>` — which it doesn't, so every\n// such page would fail its own route check. `any` makes `ctx` compatible either way.\ntype ValidateRoute<R> = R extends {\n path: infer P extends string;\n component: () => Promise<{ default: PageComponent<infer CP> }>;\n}\n ? [PageProps<P, any>] extends [CP]\n ? R\n : R & { component: `component props are not satisfied by PageProps<'${P}'>` }\n : R;\n\ntype ValidateRoutes<TRoutes extends readonly Route[]> = { [K in keyof TRoutes]: ValidateRoute<TRoutes[K]> };\n\n/**\n * Declares the app's route table. Default-export the result as `routes` from\n * `src/routes.ts` — the one file rshono requires.\n *\n * `routes.ts` only ever runs on the server, so importing server-only modules\n * from it (e.g. inside `staticPaths`) is safe.\n *\n * Beyond typing the config, this cross-checks every page against its own path:\n * if a component's props aren't satisfied by `PageProps<'<its path>'>`, the\n * `component` field errors with `component props are not satisfied by\n * PageProps<'/…'>`. Fix it by matching the page's `PageProps<Path>` type\n * argument to the path it's mounted at.\n *\n * @param config - A {@link RouteConfig}, or a bare {@link Route} array as\n * shorthand when there are no `notFound` / `error` pages.\n * @returns The config, unchanged and fully typed.\n *\n * @example\n * ```ts\n * // src/routes.ts\n * import { defineRoutes } from '@rshono/core';\n *\n * export const routes = defineRoutes({\n * routes: [\n * { path: '/', component: () => import('./components/home') },\n * { path: '/profile/:id', component: () => import('./components/profile') },\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => [{ slug: 'getting-started' }, { slug: 'deployment' }],\n * },\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') },\n * ],\n * notFound: { component: () => import('./components/404') },\n * error: { component: () => import('./components/500') },\n * });\n * ```\n *\n * @example Array shorthand\n * ```ts\n * export const routes = defineRoutes([{ path: '/', component: () => import('./components/home') }]);\n * ```\n */\nexport function defineRoutes<const TRoutes extends readonly Route[]>(\n config: RouteConfig<TRoutes> & { routes: ValidateRoutes<TRoutes> },\n): RouteConfig<TRoutes>;\nexport function defineRoutes<const TRoutes extends readonly Route[]>(routes: TRoutes & ValidateRoutes<TRoutes>): RouteConfig<TRoutes>;\nexport function defineRoutes(input: readonly Route[] | RouteConfig): RouteConfig {\n return Array.isArray(input) ? { routes: input } : (input as RouteConfig);\n}\n"]}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AA0NA;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,KAAY;IACtC,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AAwHD,MAAM,UAAU,YAAY,CAAC,KAAqC;IAChE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAE,KAAqB,CAAC;AAC3E,CAAC","sourcesContent":["import type { Env, Handler } from 'hono';\nimport type { ParamKeys, ParamKeyToRecord } from 'hono/types';\nimport type { ReactNode } from 'react';\n// Type-only, so this stays a build-time module: the import is erased and none of `context.ts`'s\n// runtime machinery (AsyncLocalStorage, hono/cookie) is pulled in by importing `@rshono/core`.\nimport type { RequestContext } from './runtime/context.js';\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\ntype UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\n\n/**\n * The `params` record implied by a route path pattern — one required `string` key\n * per `:param` segment, `Record<string, never>` for a path with no params.\n *\n * Paths use Hono's syntax, so `:id`, `:id{[0-9]+}` and `*` all work. You rarely\n * name this type directly; {@link PageProps} applies it for you.\n *\n * @typeParam P - The literal route path, e.g. `'/users/:id/posts/:postId'`.\n *\n * @example\n * ```ts\n * type P = PathParams<'/users/:id/posts/:postId'>; // { id: string; postId: string }\n * ```\n */\nexport type PathParams<P extends string> =\n ParamKeys<P> extends never ? Record<string, never> : Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P>>>>;\n\n/**\n * Props every page component receives. Pass the route's path as the type\n * argument to get `params` typed key-by-key; without it `params` falls back to\n * an open `Record<string, string>`.\n *\n * `defineRoutes` checks each page's props against `PageProps<path>` at compile\n * time, so a mismatched path literal is a type error at the route definition.\n *\n * The location props (`url` and `params`) mirror what a `'use client'` component\n * gets from `useNavigation()` — same names, same types — so moving a read across\n * the server/client line is a copy-paste.\n *\n * @typeParam Path - The literal path this page is mounted at, e.g. `'/profile/:id'`.\n * @typeParam E - The app's Hono {@link Env}, to type {@link RequestContext.var} and\n * {@link RequestContext.env} on {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { PageProps } from '@rshono/core';\n *\n * export default async function Profile({ params, url }: PageProps<'/profile/:id'>) {\n * const user = await db.getUser(params.id); // params.id is string\n * const tab = url.searchParams.get('tab') ?? 'overview';\n * return <Layout>{user.name} — {tab}</Layout>;\n * }\n * ```\n */\nexport interface PageProps<Path extends string = string, E extends Env = Env> {\n /**\n * The absolute browser-facing request {@link URL}, proxy-header aware\n * (`X-Forwarded-Host` / `-Proto`). Read `url.pathname`, `url.searchParams` and\n * the rest off it.\n *\n * A fresh instance per request that nothing else holds, so mutating it is local\n * to the page — but note it is *not* serializable, so a `'use client'` component\n * has to be handed `url.href` rather than `url`.\n *\n * On a prerendered page it is the build-time URL: a `render: 'static'` route is\n * rendered once, against `siteUrl` and with no query string, and that one file\n * then answers every request whatever its own query. So `url.searchParams` is\n * always empty there — read the query from `useNavigation().url` in a\n * `'use client'` component instead, or mark the route `render: 'dynamic'`.\n */\n url: URL;\n /** Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. */\n params: string extends Path ? Record<string, string> : PathParams<Path>;\n /**\n * The request context — the very object `getRequestContext()` returns, handed to the\n * page so cookies, headers, env and middleware variables are reachable without\n * an import.\n *\n * Server-only, and never serialized: React renders a server component and puts\n * its *output* on the wire, not its props. It is also deliberately a\n * non-enumerable property, which has three consequences worth knowing:\n *\n * - It **cannot be handed to a `'use client'` component** — it wraps the live\n * request and response, which do not exist in the browser. Passing it\n * explicitly (`<Counter ctx={ctx} />`) fails the render with React's *\"Only\n * plain objects … can be passed to Client Components\"*. Read what you need on\n * the server and pass plain values down.\n * - Spreading the page's props instead (`<Counter {...props} />`) drops `ctx`\n * silently rather than failing, since the spread copies enumerables only.\n * (That spread still fails, mind — on `url`, which is enumerable and just as\n * unserializable. Pass the values you need.)\n * - `Object.keys(props)`, `JSON.stringify(props)` and friends don't see it.\n *\n * Reading it on a `render: 'static'` route throws: a prerendered page has no\n * per-request context at build time. Mark the route `render: 'dynamic'` (or use\n * the `url` / `params` props, which are available either way — with the\n * build-time caveats noted on `url`).\n *\n * @example\n * ```tsx\n * export default function Dashboard({ ctx }: PageProps) {\n * const session = ctx.cookies.get('session');\n * if (!session) redirect('/login');\n * return <Layout>Signed in as {session}</Layout>;\n * }\n * ```\n */\n ctx: RequestContext<E>;\n}\n\n/**\n * A page: a React **server component** that renders the entire document\n * (`<html>…</html>`), usually via a shared layout. It may be `async` and await\n * data directly.\n *\n * Each page module must default-export exactly one of these. Interactive parts\n * belong in `'use client'` components the page imports — only those ship JS.\n *\n * @typeParam P - The component's props; for a page these are {@link PageProps}.\n */\nexport type PageComponent<P = any> = (props: P) => ReactNode | Promise<ReactNode>;\n\n/**\n * The shape an `{ type: 'endpoint' }` route's server module must have: a single\n * named `handler` export. The module only ever loads on the server, so it is\n * safe to import a database client or read secrets from it.\n *\n * @example\n * ```ts\n * // src/health.ts\n * import type { Handler } from 'hono';\n *\n * export const handler: Handler = (c) => c.json({ ok: true });\n * ```\n */\nexport interface EndpointServerModule {\n /** A Hono {@link Handler} handling every request matched by the route. */\n handler: Handler;\n}\n\n/**\n * A page route — a path rendered by a server component. This is the default\n * route kind, so `type` can be omitted.\n *\n * @example\n * ```ts\n * { path: '/profile/:id', component: () => import('./components/profile') }\n * ```\n */\nexport interface PageRoute {\n /** Discriminates a page from an endpoint; optional because `'page'` is the default. */\n type?: 'page';\n /** Hono-style path pattern, e.g. `/`, `/profile/:id`, `/files/*`. */\n path: string;\n /**\n * Dynamic import of the page module, whose default export is the\n * {@link PageComponent}.\n *\n * Write it inline as shown — the framework detects that exact\n * `() => import('…')` form and injects Rspack's `'use server-entry'`\n * directive into the module for you (that directive is what attaches the\n * page's client JS/CSS, giving per-page code splitting). If you wire the\n * component up any other way — a variable, a barrel re-export, a computed\n * specifier — add `'use server-entry'` as the first line of the page module\n * yourself; the framework throws a descriptive error when neither happened.\n */\n component: () => Promise<{ default: PageComponent }>;\n /** `'static'` prerenders the route at build time; `'dynamic'` (the default) renders per request. */\n render?: 'static' | 'dynamic';\n /**\n * For a `render: 'static'` route with params: the param sets to prerender, one\n * HTML file each. Runs at build time only, on the server, so it may hit a\n * database or read the filesystem.\n *\n * A parameterised static route without `staticPaths` falls back to rendering\n * per request (with a build warning). Wildcard (`*`), optional and regex\n * params can't be prerendered.\n *\n * @example\n * ```ts\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => (await db.docs.all()).map((d) => ({ slug: d.slug })),\n * }\n * ```\n */\n staticPaths?: () => Array<Record<string, string>> | Promise<Array<Record<string, string>>>;\n}\n\n/**\n * An endpoint route — a path served by a raw Hono handler instead of a React\n * component. Use it for JSON APIs, webhooks, redirects, feeds, or anything that\n * isn't an HTML page.\n *\n * @example\n * ```ts\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') }\n * ```\n */\nexport interface EndpointRoute {\n /** Marks this route as an endpoint rather than a page. Required. */\n type: 'endpoint';\n /** Hono-style path pattern, e.g. `/api/health`, `/api/users/:id`. */\n path: string;\n /** HTTP method to match. Defaults to `'all'` — every method. */\n method?: HTTPMethod;\n /** Dynamic import of the {@link EndpointServerModule} exporting `handler`. */\n server: () => Promise<EndpointServerModule>;\n}\n\n/** HTTP methods an {@link EndpointRoute} can match. `'all'` matches every method. */\nexport type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'all';\n\n/** Any entry in the `routes` array: a {@link PageRoute} or an {@link EndpointRoute}. */\nexport type Route = PageRoute | EndpointRoute;\n\n/**\n * Type guard narrowing a {@link Route} to a {@link PageRoute}. Because `type` is\n * optional on page routes, anything not explicitly `'endpoint'` is a page.\n *\n * Framework internal — deliberately absent from `index.ts`, so it is not part of the\n * `@rshono/core` surface. The request renderer and the builder use it to split the\n * route table; an app declares its routes rather than walking them.\n *\n * @internal\n */\nexport function isPageRoute(route: Route): route is PageRoute {\n return route.type !== 'endpoint';\n}\n\n/**\n * A page the framework falls back to rather than routes to — `notFound` and\n * `error` in {@link RouteConfig}. Same contract as a {@link PageRoute}\n * `component`, without a path of its own.\n */\nexport interface FallbackPage {\n /** Dynamic import of the page module; its default export is the {@link PageComponent}. */\n component: () => Promise<{ default: PageComponent }>;\n}\n\n/**\n * The error detail handed to the `error` page. Redacted in production: the\n * message is a generic `'Internal Server Error'` and there is no `stack`. In dev\n * you get the real message plus the stack.\n */\nexport interface ErrorPageInfo {\n /** The thrown error's message in dev; `'Internal Server Error'` in production. */\n message: string;\n /** The stack trace. Present in dev only. */\n stack?: string;\n}\n\n/**\n * Props for the `error` page declared in {@link RouteConfig.error} — the usual\n * {@link PageProps} plus the redaction-aware {@link ErrorPageInfo}.\n *\n * @typeParam E - The app's Hono {@link Env}, forwarded to {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { ErrorPageProps } from '@rshono/core';\n *\n * export default function ServerError({ error }: ErrorPageProps) {\n * return <html><body><h1>Something went wrong</h1><p>{error.message}</p></body></html>;\n * }\n * ```\n */\nexport type ErrorPageProps<E extends Env = Env> = PageProps<string, E> & { error: ErrorPageInfo };\n\n/**\n * The object form accepted by {@link defineRoutes}: the route table plus the two\n * optional framework-owned pages.\n *\n * @typeParam TRoutes - Inferred tuple of route literals, which is what makes the\n * per-route `path` → props check possible.\n */\nexport interface RouteConfig<TRoutes extends readonly Route[] = readonly Route[]> {\n /** Every page and endpoint in the app, matched in order. */\n routes: TRoutes;\n /** Page rendered with a 404 status for unmatched paths and for `notFound()` calls. */\n notFound?: FallbackPage;\n /** Page rendered with a 500 status when a request throws. Receives {@link ErrorPageProps}. */\n error?: FallbackPage;\n}\n\n// `PageProps<P, any>`, not `PageProps<P>`: this check is about the *path* matching the page's\n// `params`, and pinning the Env to the default would additionally demand that a page declaring its\n// own (`PageProps<'/x', MyEnv>`, to type `ctx.var`) accept a `RequestContext<Env>` — which it doesn't, so every\n// such page would fail its own route check. `any` makes `ctx` compatible either way.\ntype ValidateRoute<R> = R extends {\n path: infer P extends string;\n component: () => Promise<{ default: PageComponent<infer CP> }>;\n}\n ? [PageProps<P, any>] extends [CP]\n ? R\n : R & { component: `component props are not satisfied by PageProps<'${P}'>` }\n : R;\n\ntype ValidateRoutes<TRoutes extends readonly Route[]> = { [K in keyof TRoutes]: ValidateRoute<TRoutes[K]> };\n\n/**\n * Declares the app's route table. Default-export the result as `routes` from\n * `src/routes.ts` — the one file rshono requires.\n *\n * `routes.ts` only ever runs on the server, so importing server-only modules\n * from it (e.g. inside `staticPaths`) is safe.\n *\n * Beyond typing the config, this cross-checks every page against its own path:\n * if a component's props aren't satisfied by `PageProps<'<its path>'>`, the\n * `component` field errors with `component props are not satisfied by\n * PageProps<'/…'>`. Fix it by matching the page's `PageProps<Path>` type\n * argument to the path it's mounted at.\n *\n * @param config - A {@link RouteConfig}, or a bare {@link Route} array as\n * shorthand when there are no `notFound` / `error` pages.\n * @returns The config, unchanged and fully typed.\n *\n * @example\n * ```ts\n * // src/routes.ts\n * import { defineRoutes } from '@rshono/core';\n *\n * export const routes = defineRoutes({\n * routes: [\n * { path: '/', component: () => import('./components/home') },\n * { path: '/profile/:id', component: () => import('./components/profile') },\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => [{ slug: 'getting-started' }, { slug: 'deployment' }],\n * },\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') },\n * ],\n * notFound: { component: () => import('./components/404') },\n * error: { component: () => import('./components/500') },\n * });\n * ```\n *\n * @example Array shorthand\n * ```ts\n * export const routes = defineRoutes([{ path: '/', component: () => import('./components/home') }]);\n * ```\n */\nexport function defineRoutes<const TRoutes extends readonly Route[]>(\n config: RouteConfig<TRoutes> & { routes: ValidateRoutes<TRoutes> },\n): RouteConfig<TRoutes>;\nexport function defineRoutes<const TRoutes extends readonly Route[]>(routes: TRoutes & ValidateRoutes<TRoutes>): RouteConfig<TRoutes>;\nexport function defineRoutes(input: readonly Route[] | RouteConfig): RouteConfig {\n return Array.isArray(input) ? { routes: input } : (input as RouteConfig);\n}\n"]}
@@ -1,16 +1,15 @@
1
1
  /**
2
2
  * `@rshono/core/client` — the browser-side surface, for use from `'use client'`
3
3
  * modules: {@link useNavigation} for the current URL and soft navigation, and
4
- * {@link Boundary} / {@link ErrorBoundary} / {@link NavigationProgress} as
5
- * components.
4
+ * {@link Boundary} / {@link ErrorBoundary} as components.
6
5
  *
7
6
  * Every export is itself a `'use client'` module, so a server component can
8
- * render {@link Boundary} or {@link NavigationProgress} directly — but the hook
9
- * needs a client component. In a server component, read the same request data
10
- * from `getContext()` in `@rshono/core/server`.
7
+ * render {@link Boundary} directly — but the hook needs a client component. In a
8
+ * server component, read the same request data from `getRequestContext()` in
9
+ * `@rshono/core/server`.
11
10
  *
12
11
  * @packageDocumentation
13
12
  */
14
- export { NavigationProgress, useNavigation, type Navigation, type NavigationProgressProps, type Router } from './navigation.js';
13
+ export { useNavigation, type NavigationRouter, type NavigationState } from './navigation.js';
15
14
  export { Boundary, ErrorBoundary, type BoundaryProps, type ErrorBoundaryProps, type ErrorFallback } from './boundaries.js';
16
15
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,uBAAuB,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAChI,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
@@ -1,16 +1,15 @@
1
1
  /**
2
2
  * `@rshono/core/client` — the browser-side surface, for use from `'use client'`
3
3
  * modules: {@link useNavigation} for the current URL and soft navigation, and
4
- * {@link Boundary} / {@link ErrorBoundary} / {@link NavigationProgress} as
5
- * components.
4
+ * {@link Boundary} / {@link ErrorBoundary} as components.
6
5
  *
7
6
  * Every export is itself a `'use client'` module, so a server component can
8
- * render {@link Boundary} or {@link NavigationProgress} directly — but the hook
9
- * needs a client component. In a server component, read the same request data
10
- * from `getContext()` in `@rshono/core/server`.
7
+ * render {@link Boundary} directly — but the hook needs a client component. In a
8
+ * server component, read the same request data from `getRequestContext()` in
9
+ * `@rshono/core/server`.
11
10
  *
12
11
  * @packageDocumentation
13
12
  */
14
- export { NavigationProgress, useNavigation } from './navigation.js';
13
+ export { useNavigation } from './navigation.js';
15
14
  export { Boundary, ErrorBoundary } from './boundaries.js';
16
15
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAA8D,MAAM,iBAAiB,CAAC;AAChI,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAmE,MAAM,iBAAiB,CAAC","sourcesContent":["/**\n * `@rshono/core/client` — the browser-side surface, for use from `'use client'`\n * modules: {@link useNavigation} for the current URL and soft navigation, and\n * {@link Boundary} / {@link ErrorBoundary} / {@link NavigationProgress} as\n * components.\n *\n * Every export is itself a `'use client'` module, so a server component can\n * render {@link Boundary} or {@link NavigationProgress} directly — but the hook\n * needs a client component. In a server component, read the same request data\n * from `getContext()` in `@rshono/core/server`.\n *\n * @packageDocumentation\n */\n\nexport { NavigationProgress, useNavigation, type Navigation, type NavigationProgressProps, type Router } from './navigation.js';\nexport { Boundary, ErrorBoundary, type BoundaryProps, type ErrorBoundaryProps, type ErrorFallback } from './boundaries.js';\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAA+C,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAmE,MAAM,iBAAiB,CAAC","sourcesContent":["/**\n * `@rshono/core/client` — the browser-side surface, for use from `'use client'`\n * modules: {@link useNavigation} for the current URL and soft navigation, and\n * {@link Boundary} / {@link ErrorBoundary} as components.\n *\n * Every export is itself a `'use client'` module, so a server component can\n * render {@link Boundary} directly — but the hook needs a client component. In a\n * server component, read the same request data from `getRequestContext()` in\n * `@rshono/core/server`.\n *\n * @packageDocumentation\n */\n\nexport { useNavigation, type NavigationRouter, type NavigationState } from './navigation.js';\nexport { Boundary, ErrorBoundary, type BoundaryProps, type ErrorBoundaryProps, type ErrorFallback } from './boundaries.js';\n"]}