@rangojs/router 0.0.0-experimental.9c9afef3 → 0.0.0-experimental.a014d2b7

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 (402) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +245 -49
  3. package/dist/bin/rango.js +440 -133
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3373 -1176
  6. package/dist/vite/index.js.bak +5448 -0
  7. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  8. package/package.json +68 -14
  9. package/skills/api-client/SKILL.md +211 -0
  10. package/skills/breadcrumbs/SKILL.md +64 -2
  11. package/skills/bundle-analysis/SKILL.md +159 -0
  12. package/skills/cache-guide/SKILL.md +224 -32
  13. package/skills/caching/SKILL.md +279 -17
  14. package/skills/composability/SKILL.md +27 -3
  15. package/skills/css/SKILL.md +76 -0
  16. package/skills/debug-manifest/SKILL.md +4 -2
  17. package/skills/document-cache/SKILL.md +78 -55
  18. package/skills/handler-use/SKILL.md +364 -0
  19. package/skills/hooks/SKILL.md +250 -30
  20. package/skills/host-router/SKILL.md +83 -23
  21. package/skills/i18n/SKILL.md +276 -0
  22. package/skills/intercept/SKILL.md +87 -18
  23. package/skills/layout/SKILL.md +35 -9
  24. package/skills/links/SKILL.md +249 -17
  25. package/skills/loader/SKILL.md +235 -9
  26. package/skills/middleware/SKILL.md +52 -13
  27. package/skills/migrate-nextjs/SKILL.md +584 -0
  28. package/skills/migrate-react-router/SKILL.md +771 -0
  29. package/skills/mime-routes/SKILL.md +28 -1
  30. package/skills/observability/SKILL.md +172 -0
  31. package/skills/parallel/SKILL.md +77 -7
  32. package/skills/prerender/SKILL.md +172 -125
  33. package/skills/rango/SKILL.md +251 -22
  34. package/skills/react-compiler/SKILL.md +168 -0
  35. package/skills/response-routes/SKILL.md +123 -48
  36. package/skills/route/SKILL.md +70 -5
  37. package/skills/router-setup/SKILL.md +65 -8
  38. package/skills/scripts/SKILL.md +179 -0
  39. package/skills/server-actions/SKILL.md +775 -0
  40. package/skills/streams-and-websockets/SKILL.md +283 -0
  41. package/skills/tailwind/SKILL.md +27 -3
  42. package/skills/testing/SKILL.md +130 -0
  43. package/skills/testing/bindings.md +103 -0
  44. package/skills/testing/cache-prerender.md +127 -0
  45. package/skills/testing/client-components.md +124 -0
  46. package/skills/testing/e2e-parity.md +125 -0
  47. package/skills/testing/flight.md +91 -0
  48. package/skills/testing/handles.md +129 -0
  49. package/skills/testing/loader.md +128 -0
  50. package/skills/testing/middleware.md +99 -0
  51. package/skills/testing/render-handler.md +122 -0
  52. package/skills/testing/response-routes.md +95 -0
  53. package/skills/testing/reverse-and-types.md +84 -0
  54. package/skills/testing/server-actions.md +107 -0
  55. package/skills/testing/server-tree.md +128 -0
  56. package/skills/testing/setup.md +123 -0
  57. package/skills/typesafety/SKILL.md +322 -29
  58. package/skills/use-cache/SKILL.md +57 -14
  59. package/skills/view-transitions/SKILL.md +337 -0
  60. package/src/__augment-tests__/augment.ts +81 -0
  61. package/src/__augment-tests__/augmented.check.ts +116 -0
  62. package/src/__internal.ts +1 -66
  63. package/src/browser/action-coordinator.ts +53 -36
  64. package/src/browser/action-fence.ts +47 -0
  65. package/src/browser/app-shell.ts +39 -0
  66. package/src/browser/app-version.ts +14 -0
  67. package/src/browser/connection-warmup.ts +134 -0
  68. package/src/browser/cookie-name.ts +140 -0
  69. package/src/browser/event-controller.ts +192 -150
  70. package/src/browser/history-state.ts +21 -0
  71. package/src/browser/index.ts +3 -3
  72. package/src/browser/invalidate-client-cache.ts +52 -0
  73. package/src/browser/navigation-bridge.ts +131 -30
  74. package/src/browser/navigation-client.ts +186 -100
  75. package/src/browser/navigation-store-handle.ts +38 -0
  76. package/src/browser/navigation-store.ts +157 -74
  77. package/src/browser/navigation-transaction.ts +9 -59
  78. package/src/browser/network-error-handler.ts +34 -7
  79. package/src/browser/partial-update.ts +165 -112
  80. package/src/browser/prefetch/cache.ts +205 -62
  81. package/src/browser/prefetch/fetch.ts +347 -39
  82. package/src/browser/prefetch/queue.ts +42 -8
  83. package/src/browser/rango-state.ts +158 -76
  84. package/src/browser/react/Link.tsx +102 -15
  85. package/src/browser/react/NavigationProvider.tsx +295 -119
  86. package/src/browser/react/ScrollRestoration.tsx +10 -6
  87. package/src/browser/react/context.ts +7 -2
  88. package/src/browser/react/deferred-handle-resolution.ts +75 -0
  89. package/src/browser/react/filter-segment-order.ts +66 -7
  90. package/src/browser/react/index.ts +0 -48
  91. package/src/browser/react/location-state-shared.ts +178 -8
  92. package/src/browser/react/location-state.ts +39 -14
  93. package/src/browser/react/use-action.ts +6 -15
  94. package/src/browser/react/use-handle.ts +23 -69
  95. package/src/browser/react/use-href.tsx +8 -1
  96. package/src/browser/react/use-link-status.ts +33 -8
  97. package/src/browser/react/use-navigation.ts +32 -7
  98. package/src/browser/react/use-params.ts +20 -10
  99. package/src/browser/react/use-reverse.ts +106 -0
  100. package/src/browser/react/use-router.ts +46 -11
  101. package/src/browser/react/use-search-params.ts +0 -5
  102. package/src/browser/react/use-segments.ts +11 -21
  103. package/src/browser/response-adapter.ts +99 -8
  104. package/src/browser/rsc-router.tsx +114 -24
  105. package/src/browser/scroll-restoration.ts +37 -22
  106. package/src/browser/segment-reconciler.ts +36 -14
  107. package/src/browser/segment-structure-assert.ts +2 -2
  108. package/src/browser/server-action-bridge.ts +222 -72
  109. package/src/browser/types.ts +102 -12
  110. package/src/browser/validate-redirect-origin.ts +43 -16
  111. package/src/build/collect-fallback-refs.ts +107 -0
  112. package/src/build/generate-manifest.ts +65 -40
  113. package/src/build/generate-route-types.ts +5 -1
  114. package/src/build/index.ts +8 -2
  115. package/src/build/prefix-tree-utils.ts +123 -0
  116. package/src/build/route-trie.ts +165 -36
  117. package/src/build/route-types/ast-route-extraction.ts +15 -8
  118. package/src/build/route-types/codegen.ts +16 -5
  119. package/src/build/route-types/include-resolution.ts +125 -24
  120. package/src/build/route-types/param-extraction.ts +6 -3
  121. package/src/build/route-types/per-module-writer.ts +22 -6
  122. package/src/build/route-types/router-processing.ts +260 -94
  123. package/src/build/route-types/scan-filter.ts +9 -2
  124. package/src/build/route-types/source-scan.ts +216 -0
  125. package/src/build/runtime-discovery.ts +9 -20
  126. package/src/cache/cache-error.ts +104 -0
  127. package/src/cache/cache-key-utils.ts +29 -13
  128. package/src/cache/cache-policy.ts +108 -34
  129. package/src/cache/cache-runtime.ts +224 -41
  130. package/src/cache/cache-scope.ts +188 -82
  131. package/src/cache/cache-tag.ts +103 -0
  132. package/src/cache/cf/cf-base64.ts +33 -0
  133. package/src/cache/cf/cf-cache-constants.ts +127 -0
  134. package/src/cache/cf/cf-cache-store.ts +1989 -378
  135. package/src/cache/cf/cf-cache-types.ts +349 -0
  136. package/src/cache/cf/cf-kv-utils.ts +46 -0
  137. package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
  138. package/src/cache/cf/index.ts +6 -16
  139. package/src/cache/document-cache.ts +89 -21
  140. package/src/cache/handle-snapshot.ts +70 -0
  141. package/src/cache/index.ts +10 -20
  142. package/src/cache/memory-segment-store.ts +136 -37
  143. package/src/cache/profile-registry.ts +46 -31
  144. package/src/cache/read-through-swr.ts +56 -12
  145. package/src/cache/segment-codec.ts +9 -17
  146. package/src/cache/tag-invalidation.ts +230 -0
  147. package/src/cache/types.ts +37 -100
  148. package/src/client.rsc.tsx +44 -21
  149. package/src/client.tsx +119 -290
  150. package/src/cloudflare/index.ts +11 -0
  151. package/src/cloudflare/tracing.ts +109 -0
  152. package/src/component-utils.ts +19 -0
  153. package/src/components/DefaultDocument.tsx +8 -2
  154. package/src/context-var.ts +18 -6
  155. package/src/decode-loader-results.ts +52 -0
  156. package/src/defer.ts +196 -0
  157. package/src/deps/ssr.ts +0 -1
  158. package/src/encode-kv.ts +49 -0
  159. package/src/errors.ts +30 -4
  160. package/src/escape-script.ts +52 -0
  161. package/src/handle.ts +70 -22
  162. package/src/handles/MetaTags.tsx +62 -19
  163. package/src/handles/Scripts.tsx +183 -0
  164. package/src/handles/breadcrumbs.ts +37 -8
  165. package/src/handles/is-thenable.ts +19 -0
  166. package/src/handles/meta.ts +51 -40
  167. package/src/handles/script.ts +244 -0
  168. package/src/host/cookie-handler.ts +9 -60
  169. package/src/host/errors.ts +0 -24
  170. package/src/host/index.ts +8 -2
  171. package/src/host/pattern-matcher.ts +23 -52
  172. package/src/host/router.ts +107 -99
  173. package/src/host/testing.ts +40 -27
  174. package/src/host/types.ts +37 -4
  175. package/src/host/utils.ts +1 -1
  176. package/src/href-client.ts +137 -22
  177. package/src/index.rsc.ts +99 -13
  178. package/src/index.ts +139 -19
  179. package/src/internal-debug.ts +11 -10
  180. package/src/loader-store.ts +500 -0
  181. package/src/loader.rsc.ts +20 -13
  182. package/src/loader.ts +12 -11
  183. package/src/missing-id-error.ts +68 -0
  184. package/src/outlet-context.ts +1 -1
  185. package/src/outlet-provider.tsx +1 -5
  186. package/src/prerender/param-hash.ts +16 -16
  187. package/src/prerender/store.ts +37 -41
  188. package/src/prerender.ts +198 -82
  189. package/src/redirect-origin.ts +100 -0
  190. package/src/regex-escape.ts +8 -0
  191. package/src/render-error-thrower.tsx +20 -0
  192. package/src/response-utils.ts +62 -0
  193. package/src/reverse.ts +65 -15
  194. package/src/root-error-boundary.tsx +1 -19
  195. package/src/route-content-wrapper.tsx +19 -77
  196. package/src/route-definition/dsl-helpers.ts +461 -304
  197. package/src/route-definition/helper-factories.ts +28 -140
  198. package/src/route-definition/helpers-types.ts +143 -69
  199. package/src/route-definition/index.ts +4 -2
  200. package/src/route-definition/redirect.ts +51 -10
  201. package/src/route-definition/resolve-handler-use.ts +160 -0
  202. package/src/route-definition/use-item-types.ts +29 -0
  203. package/src/route-map-builder.ts +0 -16
  204. package/src/route-types.ts +37 -46
  205. package/src/router/basename.ts +14 -0
  206. package/src/router/content-negotiation.ts +164 -17
  207. package/src/router/error-handling.ts +45 -18
  208. package/src/router/find-match.ts +44 -23
  209. package/src/router/handler-context.ts +52 -31
  210. package/src/router/instrument.ts +350 -0
  211. package/src/router/intercept-resolution.ts +48 -24
  212. package/src/router/lazy-includes.ts +15 -52
  213. package/src/router/loader-resolution.ts +268 -56
  214. package/src/router/logging.ts +0 -6
  215. package/src/router/manifest.ts +40 -42
  216. package/src/router/match-api.ts +124 -204
  217. package/src/router/match-context.ts +0 -22
  218. package/src/router/match-handlers.ts +58 -58
  219. package/src/router/match-middleware/background-revalidation.ts +40 -24
  220. package/src/router/match-middleware/cache-lookup.ts +170 -276
  221. package/src/router/match-middleware/cache-store.ts +64 -52
  222. package/src/router/match-middleware/intercept-resolution.ts +0 -22
  223. package/src/router/match-middleware/segment-resolution.ts +45 -14
  224. package/src/router/match-pipelines.ts +1 -42
  225. package/src/router/match-result.ts +87 -39
  226. package/src/router/metrics.ts +0 -34
  227. package/src/router/middleware-types.ts +7 -140
  228. package/src/router/middleware.ts +266 -169
  229. package/src/router/navigation-snapshot.ts +131 -0
  230. package/src/router/params-util.ts +23 -0
  231. package/src/router/pattern-matching.ts +132 -90
  232. package/src/router/prefetch-cache-ttl.ts +51 -0
  233. package/src/router/prerender-match.ts +195 -56
  234. package/src/router/preview-match.ts +32 -102
  235. package/src/router/request-classification.ts +276 -0
  236. package/src/router/revalidation.ts +123 -73
  237. package/src/router/route-snapshot.ts +244 -0
  238. package/src/router/router-context.ts +3 -28
  239. package/src/router/router-interfaces.ts +115 -35
  240. package/src/router/router-options.ts +172 -15
  241. package/src/router/router-registry.ts +2 -5
  242. package/src/router/segment-resolution/fresh.ts +162 -84
  243. package/src/router/segment-resolution/helpers.ts +86 -6
  244. package/src/router/segment-resolution/loader-cache.ts +76 -39
  245. package/src/router/segment-resolution/revalidation.ts +351 -321
  246. package/src/router/segment-resolution/static-store.ts +19 -5
  247. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  248. package/src/router/segment-resolution/view-transition-default.ts +56 -0
  249. package/src/router/segment-resolution.ts +5 -1
  250. package/src/router/segment-wrappers.ts +6 -5
  251. package/src/router/state-cookie-name.ts +33 -0
  252. package/src/router/substitute-pattern-params.ts +56 -0
  253. package/src/router/telemetry-otel.ts +161 -199
  254. package/src/router/telemetry.ts +96 -19
  255. package/src/router/timeout.ts +0 -20
  256. package/src/router/tracing.ts +206 -0
  257. package/src/router/trie-matching.ts +163 -59
  258. package/src/router/types.ts +9 -63
  259. package/src/router/url-params.ts +44 -0
  260. package/src/router.ts +157 -54
  261. package/src/rsc/handler-context.ts +3 -2
  262. package/src/rsc/handler.ts +655 -529
  263. package/src/rsc/helpers.ts +168 -46
  264. package/src/rsc/index.ts +2 -5
  265. package/src/rsc/json-route-result.ts +38 -0
  266. package/src/rsc/loader-fetch.ts +122 -31
  267. package/src/rsc/manifest-init.ts +33 -42
  268. package/src/rsc/origin-guard.ts +39 -25
  269. package/src/rsc/progressive-enhancement.ts +131 -14
  270. package/src/rsc/redirect-guard.ts +99 -0
  271. package/src/rsc/response-cache-serve.ts +238 -0
  272. package/src/rsc/response-error.ts +79 -12
  273. package/src/rsc/response-route-handler.ts +99 -189
  274. package/src/rsc/rsc-rendering.ts +109 -74
  275. package/src/rsc/runtime-warnings.ts +23 -10
  276. package/src/rsc/server-action.ts +287 -115
  277. package/src/rsc/ssr-setup.ts +18 -2
  278. package/src/rsc/transition-gate.ts +89 -0
  279. package/src/rsc/types.ts +29 -9
  280. package/src/runtime-env.ts +18 -0
  281. package/src/search-params.ts +35 -30
  282. package/src/segment-content-promise.ts +67 -0
  283. package/src/segment-loader-promise.ts +149 -0
  284. package/src/segment-system.tsx +236 -202
  285. package/src/serialize.ts +243 -0
  286. package/src/server/context.ts +224 -52
  287. package/src/server/cookie-parse.ts +32 -0
  288. package/src/server/cookie-store.ts +80 -5
  289. package/src/server/handle-store.ts +40 -38
  290. package/src/server/loader-registry.ts +38 -46
  291. package/src/server/request-context.ts +401 -173
  292. package/src/ssr/index.tsx +24 -16
  293. package/src/static-handler.ts +27 -18
  294. package/src/testing/cache-status.ts +162 -0
  295. package/src/testing/collect-handle.ts +40 -0
  296. package/src/testing/dispatch.ts +701 -0
  297. package/src/testing/dom.entry.ts +22 -0
  298. package/src/testing/e2e/fixture.ts +188 -0
  299. package/src/testing/e2e/index.ts +128 -0
  300. package/src/testing/e2e/matchers.ts +35 -0
  301. package/src/testing/e2e/page-helpers.ts +272 -0
  302. package/src/testing/e2e/parity.ts +387 -0
  303. package/src/testing/e2e/server.ts +195 -0
  304. package/src/testing/flight-matchers.ts +97 -0
  305. package/src/testing/flight-normalize.ts +11 -0
  306. package/src/testing/flight-runtime.d.ts +57 -0
  307. package/src/testing/flight-tree.ts +682 -0
  308. package/src/testing/flight.entry.ts +52 -0
  309. package/src/testing/flight.ts +257 -0
  310. package/src/testing/generated-routes.ts +183 -0
  311. package/src/testing/index.ts +105 -0
  312. package/src/testing/internal/context.ts +371 -0
  313. package/src/testing/internal/flight-client-globals.ts +30 -0
  314. package/src/testing/internal/seed-vars.ts +54 -0
  315. package/src/testing/render-handler.ts +357 -0
  316. package/src/testing/render-route.tsx +581 -0
  317. package/src/testing/run-loader.ts +385 -0
  318. package/src/testing/run-middleware.ts +205 -0
  319. package/src/testing/run-transition-when.ts +164 -0
  320. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  321. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  322. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  323. package/src/testing/vitest-stubs/version.ts +5 -0
  324. package/src/testing/vitest.ts +305 -0
  325. package/src/theme/ThemeProvider.tsx +20 -58
  326. package/src/theme/ThemeScript.tsx +7 -9
  327. package/src/theme/constants.ts +52 -13
  328. package/src/theme/index.ts +0 -7
  329. package/src/theme/theme-context.ts +1 -5
  330. package/src/theme/theme-script.ts +22 -21
  331. package/src/theme/use-theme.ts +0 -3
  332. package/src/types/boundaries.ts +0 -35
  333. package/src/types/cache-types.ts +17 -8
  334. package/src/types/error-types.ts +30 -90
  335. package/src/types/global-namespace.ts +54 -41
  336. package/src/types/handler-context.ts +125 -71
  337. package/src/types/index.ts +3 -10
  338. package/src/types/loader-types.ts +40 -11
  339. package/src/types/request-scope.ts +112 -0
  340. package/src/types/route-config.ts +6 -50
  341. package/src/types/route-entry.ts +12 -7
  342. package/src/types/segments.ts +136 -15
  343. package/src/urls/include-helper.ts +33 -70
  344. package/src/urls/index.ts +1 -11
  345. package/src/urls/path-helper-types.ts +68 -18
  346. package/src/urls/path-helper.ts +57 -111
  347. package/src/urls/pattern-types.ts +48 -19
  348. package/src/urls/response-types.ts +25 -22
  349. package/src/urls/type-extraction.ts +58 -139
  350. package/src/urls/urls-function.ts +1 -19
  351. package/src/use-loader.tsx +346 -89
  352. package/src/vite/debug.ts +185 -0
  353. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  354. package/src/vite/discovery/discover-routers.ts +130 -85
  355. package/src/vite/discovery/discovery-errors.ts +194 -0
  356. package/src/vite/discovery/gate-state.ts +171 -0
  357. package/src/vite/discovery/prerender-collection.ts +214 -132
  358. package/src/vite/discovery/route-types-writer.ts +40 -84
  359. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  360. package/src/vite/discovery/state.ts +57 -4
  361. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  362. package/src/vite/index.ts +6 -0
  363. package/src/vite/inject-client-debug.ts +36 -0
  364. package/src/vite/plugin-types.ts +178 -5
  365. package/src/vite/plugins/cjs-to-esm.ts +16 -19
  366. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  367. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  368. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  369. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  370. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  371. package/src/vite/plugins/expose-action-id.ts +48 -95
  372. package/src/vite/plugins/expose-id-utils.ts +96 -51
  373. package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
  374. package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
  375. package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
  376. package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
  377. package/src/vite/plugins/expose-internal-ids.ts +553 -317
  378. package/src/vite/plugins/performance-tracks.ts +64 -170
  379. package/src/vite/plugins/refresh-cmd.ts +89 -27
  380. package/src/vite/plugins/use-cache-transform.ts +73 -83
  381. package/src/vite/plugins/version-injector.ts +40 -29
  382. package/src/vite/plugins/version-plugin.ts +37 -40
  383. package/src/vite/plugins/virtual-entries.ts +39 -25
  384. package/src/vite/rango.ts +118 -114
  385. package/src/vite/router-discovery.ts +941 -142
  386. package/src/vite/utils/ast-handler-extract.ts +26 -35
  387. package/src/vite/utils/banner.ts +1 -1
  388. package/src/vite/utils/bundle-analysis.ts +10 -15
  389. package/src/vite/utils/client-chunks.ts +184 -0
  390. package/src/vite/utils/directive-prologue.ts +40 -0
  391. package/src/vite/utils/forward-user-plugins.ts +171 -0
  392. package/src/vite/utils/manifest-utils.ts +4 -59
  393. package/src/vite/utils/package-resolution.ts +20 -52
  394. package/src/vite/utils/prerender-utils.ts +81 -34
  395. package/src/vite/utils/shared-utils.ts +92 -42
  396. package/src/browser/action-response-classifier.ts +0 -99
  397. package/src/browser/debug-channel.ts +0 -93
  398. package/src/browser/react/use-client-cache.ts +0 -58
  399. package/src/browser/shallow.ts +0 -40
  400. package/src/handles/index.ts +0 -7
  401. package/src/network-error-thrower.tsx +0 -23
  402. package/src/router/middleware-cookies.ts +0 -55
@@ -0,0 +1,44 @@
1
+ /**
2
+ * URL param encode/decode at the route boundary.
3
+ *
4
+ * Extraction (decode): regex/trie matchers keep param values URL-encoded;
5
+ * `safeDecodeURIComponent` turns them back into raw strings so `ctx.params`
6
+ * matches the contract apps expect (Express/React Router/Fastify/Koa) and
7
+ * round-trips through reverse stay stable. Malformed %-encoding is
8
+ * preserved as-is so a broken URL doesn't crash matching.
9
+ *
10
+ * Reversal (encode): `encodePathSegment` escapes only what RFC 3986
11
+ * requires for a path segment — `/`, `?`, `#`, space, control chars,
12
+ * non-ASCII — and leaves pchar sub-delims (`@ : $ & + , ; =` and friends)
13
+ * readable. `encodeURIComponent` over-encodes for path segments, which
14
+ * makes generated URLs harder for humans to read in the address bar
15
+ * (e.g. mailbox IDs like `ivo@example.com` would become
16
+ * `ivo%40example.com` even though `@` is path-legal).
17
+ */
18
+
19
+ export function safeDecodeURIComponent(raw: string): string {
20
+ if (raw === "" || raw.indexOf("%") === -1) return raw;
21
+ try {
22
+ return decodeURIComponent(raw);
23
+ } catch {
24
+ return raw;
25
+ }
26
+ }
27
+
28
+ const PATH_SAFE_ESCAPES: Record<string, string> = {
29
+ "%3A": ":",
30
+ "%40": "@",
31
+ "%24": "$",
32
+ "%26": "&",
33
+ "%2B": "+",
34
+ "%2C": ",",
35
+ "%3B": ";",
36
+ "%3D": "=",
37
+ };
38
+
39
+ export function encodePathSegment(value: string): string {
40
+ return encodeURIComponent(value).replace(
41
+ /%(?:3A|40|24|26|2B|2C|3B|3D)/gi,
42
+ (match) => PATH_SAFE_ESCAPES[match.toUpperCase()] ?? match,
43
+ );
44
+ }
package/src/router.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { createCacheScope } from "./cache/cache-scope.js";
3
- import {
4
- setCacheProfiles,
5
- resolveCacheProfiles,
6
- } from "./cache/profile-registry.js";
3
+ import { resolveCacheProfiles } from "./cache/profile-registry.js";
7
4
  import { isCachedFunction } from "./cache/taint.js";
8
5
  import { assertClientComponent } from "./component-utils.js";
9
6
  import { DefaultDocument } from "./components/DefaultDocument.js";
@@ -19,11 +16,13 @@ import {
19
16
  import MapRootLayout from "./server/root-layout.js";
20
17
  import type { AllUseItems } from "./route-types.js";
21
18
  import type { UrlPatterns } from "./urls.js";
19
+ import type { UrlBuilder } from "./urls/pattern-types.js";
20
+ import { urls } from "./urls.js";
21
+ import { buildPrecomputedByPrefix } from "./build/prefix-tree-utils.js";
22
22
  import {
23
- EntryData,
24
- InterceptSelectorContext,
23
+ type EntryData,
25
24
  getContext,
26
- RSCRouterContext,
25
+ RangoContext,
27
26
  type MetricsStore,
28
27
  } from "./server/context";
29
28
  import { createHandleStore, type HandleStore } from "./server/handle-store.js";
@@ -55,6 +54,7 @@ import { buildDebugManifest } from "./router/debug-manifest.js";
55
54
 
56
55
  import type { SegmentResolutionDeps, MatchApiDeps } from "./router/types.js";
57
56
  import { createHandlerContext } from "./router/handler-context.js";
57
+ import { normalizeBasename } from "./router/basename.js";
58
58
  import {
59
59
  setupLoaderAccess,
60
60
  setupLoaderAccessSilent,
@@ -63,15 +63,17 @@ import {
63
63
  import { loadManifest } from "./router/manifest.js";
64
64
  import { createMetricsStore } from "./router/metrics.js";
65
65
  import {
66
- parsePattern,
66
+ compileMiddlewarePattern,
67
67
  type MiddlewareEntry,
68
68
  type MiddlewareFn,
69
69
  } from "./router/middleware.js";
70
70
  import {
71
71
  extractStaticPrefix,
72
+ joinPrefix,
72
73
  traverseBack,
73
74
  } from "./router/pattern-matching.js";
74
75
  import { resolveSink, safeEmit, getRequestId } from "./router/telemetry.js";
76
+ import { resolveTracing } from "./router/tracing.js";
75
77
  import { evaluateRevalidation } from "./router/revalidation.js";
76
78
  import {
77
79
  type RouterContext,
@@ -89,13 +91,10 @@ import {
89
91
  RouterRegistry,
90
92
  nextRouterAutoId,
91
93
  } from "./router/router-registry.js";
94
+ import type { RangoOptions, RootLayoutProps } from "./router/router-options.js";
92
95
  import type {
93
- RSCRouterOptions,
94
- RootLayoutProps,
95
- } from "./router/router-options.js";
96
- import type {
97
- RSCRouter,
98
- RSCRouterInternal,
96
+ Rango,
97
+ RangoInternal,
99
98
  RouterRequestInput,
100
99
  } from "./router/router-interfaces.js";
101
100
 
@@ -110,29 +109,32 @@ import {
110
109
  matchForPrerender as _matchForPrerender,
111
110
  renderStaticSegment as _renderStaticSegment,
112
111
  } from "./router/prerender-match.js";
112
+ import { resolveStateCookieName } from "./router/state-cookie-name.js";
113
+ import { resolvePrefetchCacheTTL } from "./router/prefetch-cache-ttl.js";
113
114
 
114
115
  // Re-export public types and values from extracted modules
115
116
  export { RSC_ROUTER_BRAND, RouterRegistry } from "./router/router-registry.js";
116
117
  export type {
117
- RSCRouterOptions,
118
+ RangoOptions,
118
119
  RootLayoutProps,
119
120
  SSRStreamMode,
120
121
  SSROptions,
121
122
  ResolveStreamingContext,
122
123
  } from "./router/router-options.js";
123
124
  export type {
124
- RSCRouter,
125
- RSCRouterInternal,
125
+ Rango,
126
+ RangoInternal,
126
127
  RouterRequestInput,
127
128
  } from "./router/router-interfaces.js";
128
129
  export { toInternal } from "./router/router-interfaces.js";
129
130
 
130
131
  export function createRouter<TEnv = any>(
131
- options: RSCRouterOptions<TEnv> = {},
132
- ): RSCRouter<TEnv, {}> {
132
+ options: RangoOptions<TEnv> = {},
133
+ ): Rango<TEnv, {}> {
133
134
  const {
134
135
  id: userProvidedId,
135
136
  $$id: injectedId,
137
+ basename: basenameOption,
136
138
  debugPerformance = false,
137
139
  document: documentOption,
138
140
  defaultErrorBoundary,
@@ -148,24 +150,46 @@ export function createRouter<TEnv = any>(
148
150
  nonce,
149
151
  version,
150
152
  prefetchCacheTTL: prefetchCacheTTLOption,
153
+ stateCookiePrefix: stateCookiePrefixOption,
151
154
  warmup: warmupOption,
152
155
  allowDebugManifest: allowDebugManifestOption = false,
153
156
  telemetry: telemetrySink,
157
+ tracing: tracingOption,
154
158
  ssr: ssrOption,
155
159
  timeout: timeoutShorthand,
156
160
  timeouts: timeoutsOption,
157
161
  onTimeout,
158
162
  originCheck: originCheckOption,
163
+ viewTransition: viewTransitionOption = "auto",
164
+ debugCacheSignal: debugCacheSignalOption = false,
165
+ strictMode: strictModeOption = true,
159
166
  } = options;
160
167
 
168
+ // Debug cache signal gate (DEVELOPMENT/TEST ONLY). Enabled by the
169
+ // debugCacheSignal option OR the RANGO_TEST_SIGNALS=1 env flag. When off,
170
+ // no X-Rango-Cache header is emitted and output is byte-identical.
171
+ const cacheSignalEnabled =
172
+ debugCacheSignalOption ||
173
+ (typeof process !== "undefined" &&
174
+ (process as { env?: Record<string, string | undefined> }).env
175
+ ?.RANGO_TEST_SIGNALS === "1");
176
+
177
+ // Normalize basename: ensure leading slash, strip trailing slash.
178
+ // A bare "/" is equivalent to no basename. Shared with the testing
179
+ // primitives via normalizeBasename so they can never drift.
180
+ const basename = normalizeBasename(basenameOption);
181
+
161
182
  // Resolve telemetry sink (no-op when not configured)
162
183
  const telemetry = resolveSink(telemetrySink);
163
184
 
164
- // Resolve cache profiles: merge user config with guaranteed default profile.
165
- // This resolved map is both stored on the router (for per-request context)
166
- // and written to the global registry (for DSL-time cache("profileName")).
185
+ // Resolve span tracing (undefined when not configured; every traceSpan() call
186
+ // is then a direct pass-through with zero behavior change).
187
+ const resolvedTracing = resolveTracing(tracingOption);
188
+
189
+ // Resolve cache profiles: merge user config with the guaranteed default
190
+ // profile. This resolved map is threaded onto each request context; the
191
+ // "use cache: <profile>" runtime path reads it request-scoped.
167
192
  const resolvedCacheProfiles = resolveCacheProfiles(cacheProfilesOption);
168
- setCacheProfiles(resolvedCacheProfiles);
169
193
 
170
194
  // Source file: prefer Vite-injected path (zero cost), fall back to
171
195
  // stack trace parsing for non-Vite environments (e.g. tests).
@@ -200,21 +224,32 @@ export function createRouter<TEnv = any>(
200
224
  const routerId =
201
225
  userProvidedId ?? injectedId ?? `router_${nextRouterAutoId()}`;
202
226
 
203
- // Resolve prefetch cache TTL (default: 300 seconds / 5 minutes)
204
- // Clamp to a non-negative integer for valid Cache-Control max-age.
205
- const rawTTL =
206
- prefetchCacheTTLOption !== undefined ? prefetchCacheTTLOption : 300;
207
- const prefetchCacheTTLSeconds =
208
- rawTTL === false ? 0 : Math.max(0, Math.floor(rawTTL));
209
- const prefetchCacheTTL = prefetchCacheTTLSeconds * 1000;
227
+ // Resolve the rango state cookie name once, here, so the two cookie writers
228
+ // (the client document.cookie writer and the server Set-Cookie writer)
229
+ // consume one pre-composed name and cannot drift.
230
+ const resolvedStateCookieName = resolveStateCookieName(
231
+ stateCookiePrefixOption,
232
+ routerId,
233
+ );
234
+
235
+ // Resolve prefetch cache TTL (default: 300 seconds / 5 minutes). Clamps to a
236
+ // non-negative integer and guards non-finite (NaN/Infinity) inputs so a
237
+ // malformed `Cache-Control: max-age=NaN` can never reach the wire.
238
+ const resolvedPrefetchCacheTTL = resolvePrefetchCacheTTL(
239
+ prefetchCacheTTLOption,
240
+ );
241
+ const prefetchCacheTTL = resolvedPrefetchCacheTTL.ms;
210
242
  const prefetchCacheControl: string | false =
211
- prefetchCacheTTLSeconds === 0
212
- ? false
213
- : `private, max-age=${prefetchCacheTTLSeconds}`;
243
+ resolvedPrefetchCacheTTL.cacheControl;
214
244
 
215
245
  // Resolve warmup enabled flag (default: true)
216
246
  const warmupEnabled = warmupOption !== false;
217
247
 
248
+ // Resolve StrictMode flag (default: true). Shipped to the client in payload
249
+ // metadata; the browser entry reads it once to decide whether to wrap the
250
+ // hydrated tree in React.StrictMode.
251
+ const strictMode = strictModeOption !== false;
252
+
218
253
  // Resolve theme config (null if theme not enabled)
219
254
  const resolvedThemeConfig = themeOption
220
255
  ? resolveThemeConfig(themeOption)
@@ -246,9 +281,14 @@ export function createRouter<TEnv = any>(
246
281
  invokeOnError(onError, error, phase, context, "Router");
247
282
  }
248
283
 
249
- // Validate document is a client component
284
+ // Validate document is a client component. Under a test runner the "use
285
+ // client" transform has not run, so a real exported document has no marker;
286
+ // allowServerInTest lets the router construct in a bare unit test (for
287
+ // dispatch / assertGeneratedRoutesMatch) while a real build still throws.
250
288
  if (documentOption !== undefined) {
251
- assertClientComponent(documentOption, "document");
289
+ assertClientComponent(documentOption, "document", {
290
+ allowServerInTest: true,
291
+ });
252
292
  }
253
293
 
254
294
  // Use default document if none provided (keeps internal name as rootLayout)
@@ -312,7 +352,7 @@ export function createRouter<TEnv = any>(
312
352
  let regex: RegExp | null = null;
313
353
  let paramNames: string[] = [];
314
354
  if (fullPattern) {
315
- const parsed = parsePattern(fullPattern);
355
+ const parsed = compileMiddlewarePattern(fullPattern);
316
356
  regex = parsed.regex;
317
357
  paramNames = parsed.paramNames;
318
358
  }
@@ -322,7 +362,6 @@ export function createRouter<TEnv = any>(
322
362
  regex,
323
363
  paramNames,
324
364
  handler,
325
- mountPrefix,
326
365
  });
327
366
  }
328
367
 
@@ -356,9 +395,11 @@ export function createRouter<TEnv = any>(
356
395
  getRouterPrecomputedEntries(routerId) ?? getPrecomputedEntries();
357
396
  if (current !== precomputedSource) {
358
397
  precomputedSource = current;
359
- precomputedByPrefix = current
360
- ? new Map(current.map((e) => [e.staticPrefix, e.routes]))
361
- : null;
398
+ // buildPrecomputedByPrefix drops any staticPrefix owned by more than one
399
+ // leaf include instead of collapsing it last-wins (which would mis-assign
400
+ // one include's routes to another's entry and 500 a valid sibling route).
401
+ // Such shared-prefix includes resolve via the handler path instead.
402
+ precomputedByPrefix = current ? buildPrecomputedByPrefix(current) : null;
362
403
  }
363
404
  return precomputedByPrefix;
364
405
  }
@@ -528,6 +569,7 @@ export function createRouter<TEnv = any>(
528
569
  findNearestNotFoundBoundary,
529
570
  notFoundComponent: notFound,
530
571
  callOnError,
572
+ viewTransitionDefault: viewTransitionOption,
531
573
  };
532
574
 
533
575
  // Match API dependencies
@@ -615,6 +657,8 @@ export function createRouter<TEnv = any>(
615
657
  params: Record<string, string>,
616
658
  buildVars?: Record<string, any>,
617
659
  isPassthroughRoute?: boolean,
660
+ buildEnv?: TEnv,
661
+ devMode?: boolean,
618
662
  ) {
619
663
  return _matchForPrerender(
620
664
  pathname,
@@ -622,6 +666,8 @@ export function createRouter<TEnv = any>(
622
666
  prerenderDeps,
623
667
  buildVars,
624
668
  isPassthroughRoute,
669
+ buildEnv,
670
+ devMode,
625
671
  );
626
672
  }
627
673
 
@@ -629,12 +675,16 @@ export function createRouter<TEnv = any>(
629
675
  handler: Function,
630
676
  handlerId: string,
631
677
  routeName?: string,
678
+ buildEnv?: TEnv,
679
+ devMode?: boolean,
632
680
  ) {
633
681
  return _renderStaticSegment<TEnv>(
634
682
  handler,
635
683
  handlerId,
636
684
  mergedRouteMap,
637
685
  routeName,
686
+ buildEnv,
687
+ devMode,
638
688
  );
639
689
  }
640
690
 
@@ -647,6 +697,7 @@ export function createRouter<TEnv = any>(
647
697
  findMatch,
648
698
  findInterceptForRoute,
649
699
  telemetry: telemetrySink,
700
+ cacheSignalEnabled,
650
701
  });
651
702
 
652
703
  const { match, matchPartial, matchError, previewMatch } = matchHandlers;
@@ -656,11 +707,18 @@ export function createRouter<TEnv = any>(
656
707
  * The type system tracks accumulated routes through the builder chain
657
708
  * Initial TRoutes is {} (empty) to avoid poisoning accumulated types with Record<string, string>
658
709
  */
659
- const router: RSCRouterInternal<TEnv, {}> = {
710
+ const router: RangoInternal<TEnv, {}> = {
660
711
  __brand: RSC_ROUTER_BRAND,
661
712
  id: routerId,
713
+ basename,
714
+
715
+ routes(patternsOrBuilder: UrlPatterns<TEnv> | UrlBuilder<TEnv>): any {
716
+ // Wrap builder functions in urls() automatically
717
+ const urlPatterns: UrlPatterns<TEnv> =
718
+ typeof patternsOrBuilder === "function"
719
+ ? (urls(patternsOrBuilder) as UrlPatterns<TEnv>)
720
+ : patternsOrBuilder;
662
721
 
663
- routes(urlPatterns: UrlPatterns<TEnv>): any {
664
722
  // Store reference for runtime manifest generation
665
723
  storedUrlPatterns = urlPatterns;
666
724
  const currentMountIndex = mountIndex++;
@@ -697,7 +755,7 @@ export function createRouter<TEnv = any>(
697
755
  };
698
756
 
699
757
  let handlerResult: AllUseItems[] = [];
700
- RSCRouterContext.run(
758
+ RangoContext.run(
701
759
  {
702
760
  manifest,
703
761
  patterns: routePatterns,
@@ -708,6 +766,10 @@ export function createRouter<TEnv = any>(
708
766
  counters: {},
709
767
  mountIndex: currentMountIndex,
710
768
  cacheProfiles: resolvedCacheProfiles,
769
+ // basename sets the initial URL prefix so all path() patterns
770
+ // are registered with the prefix (e.g. "/admin" + "/users" = "/admin/users").
771
+ // No namePrefix — route names stay unprefixed.
772
+ ...(basename ? { urlPrefix: basename } : {}),
711
773
  },
712
774
  () => {
713
775
  handlerResult = urlPatterns.handler() as AllUseItems[];
@@ -727,7 +789,7 @@ export function createRouter<TEnv = any>(
727
789
  if (entry.type === "route" && entry.isPrerender) {
728
790
  if (!prerenderRouteKeys) prerenderRouteKeys = new Set();
729
791
  prerenderRouteKeys.add(name);
730
- if (entry.prerenderDef?.options?.passthrough === true) {
792
+ if (entry.isPassthrough === true) {
731
793
  if (!passthroughRouteKeys) passthroughRouteKeys = new Set();
732
794
  passthroughRouteKeys.add(name);
733
795
  }
@@ -805,10 +867,13 @@ export function createRouter<TEnv = any>(
805
867
 
806
868
  // Create placeholder RouteEntry for each lazy include
807
869
  for (const lazyInclude of lazyIncludes) {
808
- // Compute the full URL prefix (combining parent prefix if any)
809
- const fullPrefix = lazyInclude.context.urlPrefix
810
- ? lazyInclude.context.urlPrefix + lazyInclude.prefix
811
- : lazyInclude.prefix;
870
+ // Compute the full URL prefix (combining parent prefix if any). Use the
871
+ // slash-collapsing join so a trailing-slash parent prefix does not
872
+ // produce a double-slash staticPrefix the trie's sp can never match.
873
+ const fullPrefix = joinPrefix(
874
+ lazyInclude.context.urlPrefix,
875
+ lazyInclude.prefix,
876
+ );
812
877
 
813
878
  const lazyEntry: RouteEntry<TEnv> & { _lazyPrefix?: string } = {
814
879
  prefix: "",
@@ -856,8 +921,18 @@ export function createRouter<TEnv = any>(
856
921
  patternOrMiddleware: string | MiddlewareFn<TEnv>,
857
922
  middleware?: MiddlewareFn<TEnv>,
858
923
  ): any {
859
- // Global middleware - no mount prefix
860
- addMiddleware(patternOrMiddleware, middleware, null);
924
+ // Auto-prefix pattern with basename so router-level middleware
925
+ // patterns are router-relative (e.g. "/users/*" matches "/app/users/*").
926
+ if (basename && typeof patternOrMiddleware === "string") {
927
+ const pattern = patternOrMiddleware;
928
+ const prefixed =
929
+ pattern === "/*" || pattern === "*"
930
+ ? `${basename}/*`
931
+ : `${basename}${pattern}`;
932
+ addMiddleware(prefixed, middleware, null);
933
+ } else {
934
+ addMiddleware(patternOrMiddleware, middleware, null);
935
+ }
861
936
  return router;
862
937
  },
863
938
 
@@ -894,12 +969,22 @@ export function createRouter<TEnv = any>(
894
969
  prefetchCacheControl,
895
970
  prefetchCacheTTL,
896
971
 
972
+ // Expose the resolved rango state cookie name for the server-side writer
973
+ // (invalidateClientCache) and for shipping to the client in metadata.
974
+ resolvedStateCookieName,
975
+
897
976
  // Expose warmup enabled flag for handler and client
898
977
  warmupEnabled,
899
978
 
979
+ // Expose StrictMode flag for the initial-render payload metadata
980
+ strictMode,
981
+
900
982
  // Expose router-wide performance debugging for request-level metrics setup
901
983
  debugPerformance,
902
984
 
985
+ // Expose resolved span tracing for the handler (Cloudflare custom spans)
986
+ tracing: resolvedTracing,
987
+
903
988
  // Expose debug manifest flag for handler
904
989
  allowDebugManifest: allowDebugManifestOption,
905
990
 
@@ -958,6 +1043,16 @@ export function createRouter<TEnv = any>(
958
1043
  // Expose source file for per-router type generation
959
1044
  __sourceFile,
960
1045
 
1046
+ // Expose basename for runtime manifest generation
1047
+ __basename: basename,
1048
+
1049
+ // Expose router-level boundary defaults for build-time clientChunks
1050
+ // discovery (so a "use client" default boundary lands in app-fallback).
1051
+ // These are createRouter options, never pushed onto EntryData.
1052
+ __defaultErrorBoundary: defaultErrorBoundary,
1053
+ __defaultNotFoundBoundary: defaultNotFoundBoundary,
1054
+ __notFound: notFound,
1055
+
961
1056
  // RSC request handler (lazily created on first call)
962
1057
  fetch: (() => {
963
1058
  // Handler is created on first call and reused
@@ -975,8 +1070,10 @@ export function createRouter<TEnv = any>(
975
1070
  if (!handler) {
976
1071
  // Lazy import deferred to first request to avoid dev mode issues
977
1072
  const { createRSCHandler } = await import("./rsc/handler.js");
978
- // Cast: handler.ts still accepts (request, env) will be updated
979
- // separately to accept RouterRequestInput.
1073
+ // Cast: createRSCHandler receives `router as any`, which erases TEnv
1074
+ // and infers its handler as RouterRequestInput<unknown>. Re-narrow the
1075
+ // returned handler to RouterRequestInput<TEnv> so the call below stays
1076
+ // typed. (The handler already accepts (request, RouterRequestInput).)
980
1077
  handler = createRSCHandler({
981
1078
  router: router as any,
982
1079
  cache,
@@ -991,6 +1088,10 @@ export function createRouter<TEnv = any>(
991
1088
  };
992
1089
  })(),
993
1090
 
1091
+ // Low-level route matching for request classification
1092
+ findMatch: (pathname: string, metricsStore?: any) =>
1093
+ findMatch(pathname, metricsStore),
1094
+
994
1095
  // Debug utility for manifest inspection
995
1096
  debugManifest: () => buildDebugManifest<TEnv>(routesEntries),
996
1097
  };
@@ -999,8 +1100,10 @@ export function createRouter<TEnv = any>(
999
1100
  RouterRegistry.set(routerId, router);
1000
1101
 
1001
1102
  // If urls option was provided, auto-register them
1002
- if (urlsOption) {
1003
- return router.routes(urlsOption) as RSCRouter<TEnv, {}>;
1103
+ if (typeof urlsOption === "function") {
1104
+ return router.routes(urlsOption) as Rango<TEnv, {}>;
1105
+ } else if (urlsOption) {
1106
+ return router.routes(urlsOption) as Rango<TEnv, {}>;
1004
1107
  }
1005
1108
 
1006
1109
  return router;
@@ -6,14 +6,14 @@
6
6
  * RSC rendering) so they can be standalone modules without closure coupling.
7
7
  */
8
8
 
9
- import type { RSCRouterInternal } from "../router/router-interfaces.js";
9
+ import type { RangoInternal } from "../router/router-interfaces.js";
10
10
  import type { ErrorPhase } from "../types.js";
11
11
  import type { InvokeOnErrorContext } from "../router/error-handling.js";
12
12
  import type { RSCDependencies, LoadSSRModule } from "./types.js";
13
13
  import type { SSRStreamMode } from "../router/router-options.js";
14
14
 
15
15
  export interface HandlerContext<TEnv = unknown> {
16
- router: RSCRouterInternal<TEnv, any>;
16
+ router: RangoInternal<TEnv, any>;
17
17
  version: string;
18
18
  renderToReadableStream: RSCDependencies["renderToReadableStream"];
19
19
  decodeReply: RSCDependencies["decodeReply"];
@@ -31,6 +31,7 @@ export interface HandlerContext<TEnv = unknown> {
31
31
  createRedirectFlightResponse: (
32
32
  redirectUrl: string,
33
33
  locationState?: Record<string, unknown>,
34
+ external?: boolean,
34
35
  ) => Response;
35
36
 
36
37
  /**