@rangojs/router 0.0.0-experimental.31 → 0.0.0-experimental.3232cd17

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 (376) hide show
  1. package/AGENTS.md +4 -0
  2. package/README.md +198 -44
  3. package/dist/bin/rango.js +287 -105
  4. package/dist/testing/vitest.js +82 -0
  5. package/dist/vite/index.js +3248 -1117
  6. package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  7. package/package.json +73 -21
  8. package/skills/api-client/SKILL.md +211 -0
  9. package/skills/breadcrumbs/SKILL.md +107 -1
  10. package/skills/bundle-analysis/SKILL.md +159 -0
  11. package/skills/cache-guide/SKILL.md +245 -21
  12. package/skills/caching/SKILL.md +302 -6
  13. package/skills/composability/SKILL.md +27 -2
  14. package/skills/css/SKILL.md +76 -0
  15. package/skills/document-cache/SKILL.md +78 -55
  16. package/skills/handler-use/SKILL.md +364 -0
  17. package/skills/hooks/SKILL.md +270 -30
  18. package/skills/host-router/SKILL.md +82 -22
  19. package/skills/i18n/SKILL.md +276 -0
  20. package/skills/intercept/SKILL.md +49 -5
  21. package/skills/layout/SKILL.md +35 -9
  22. package/skills/links/SKILL.md +249 -17
  23. package/skills/loader/SKILL.md +294 -30
  24. package/skills/middleware/SKILL.md +52 -13
  25. package/skills/migrate-nextjs/SKILL.md +584 -0
  26. package/skills/migrate-react-router/SKILL.md +769 -0
  27. package/skills/mime-routes/SKILL.md +27 -0
  28. package/skills/observability/SKILL.md +137 -0
  29. package/skills/parallel/SKILL.md +203 -7
  30. package/skills/prerender/SKILL.md +123 -100
  31. package/skills/rango/SKILL.md +250 -22
  32. package/skills/react-compiler/SKILL.md +168 -0
  33. package/skills/response-routes/SKILL.md +122 -47
  34. package/skills/route/SKILL.md +97 -5
  35. package/skills/router-setup/SKILL.md +90 -5
  36. package/skills/server-actions/SKILL.md +775 -0
  37. package/skills/streams-and-websockets/SKILL.md +283 -0
  38. package/skills/tailwind/SKILL.md +27 -3
  39. package/skills/testing/SKILL.md +129 -0
  40. package/skills/testing/bindings.md +89 -0
  41. package/skills/testing/cache-prerender.md +124 -0
  42. package/skills/testing/client-components.md +122 -0
  43. package/skills/testing/e2e-parity.md +125 -0
  44. package/skills/testing/flight.md +92 -0
  45. package/skills/testing/handles.md +129 -0
  46. package/skills/testing/loader.md +128 -0
  47. package/skills/testing/middleware.md +99 -0
  48. package/skills/testing/render-handler.md +121 -0
  49. package/skills/testing/response-routes.md +95 -0
  50. package/skills/testing/reverse-and-types.md +84 -0
  51. package/skills/testing/server-actions.md +107 -0
  52. package/skills/testing/server-tree.md +128 -0
  53. package/skills/testing/setup.md +120 -0
  54. package/skills/typesafety/SKILL.md +329 -27
  55. package/skills/use-cache/SKILL.md +36 -5
  56. package/skills/view-transitions/SKILL.md +294 -0
  57. package/src/__augment-tests__/augment.ts +81 -0
  58. package/src/__augment-tests__/augmented.check.ts +116 -0
  59. package/src/__internal.ts +67 -40
  60. package/src/browser/action-coordinator.ts +53 -36
  61. package/src/browser/action-fence.ts +47 -0
  62. package/src/browser/app-shell.ts +39 -0
  63. package/src/browser/app-version.ts +14 -0
  64. package/src/browser/cookie-name.ts +140 -0
  65. package/src/browser/event-controller.ts +86 -147
  66. package/src/browser/history-state.ts +21 -0
  67. package/src/browser/index.ts +3 -3
  68. package/src/browser/invalidate-client-cache.ts +52 -0
  69. package/src/browser/link-interceptor.ts +4 -0
  70. package/src/browser/navigation-bridge.ts +148 -19
  71. package/src/browser/navigation-client.ts +187 -67
  72. package/src/browser/navigation-store-handle.ts +38 -0
  73. package/src/browser/navigation-store.ts +76 -67
  74. package/src/browser/navigation-transaction.ts +18 -66
  75. package/src/browser/partial-update.ts +123 -94
  76. package/src/browser/prefetch/cache.ts +214 -36
  77. package/src/browser/prefetch/fetch.ts +260 -38
  78. package/src/browser/prefetch/policy.ts +6 -0
  79. package/src/browser/prefetch/queue.ts +126 -20
  80. package/src/browser/prefetch/resource-ready.ts +77 -0
  81. package/src/browser/rango-state.ts +158 -76
  82. package/src/browser/react/Link.tsx +93 -11
  83. package/src/browser/react/NavigationProvider.tsx +115 -34
  84. package/src/browser/react/ScrollRestoration.tsx +10 -6
  85. package/src/browser/react/context.ts +7 -2
  86. package/src/browser/react/filter-segment-order.ts +49 -7
  87. package/src/browser/react/index.ts +0 -48
  88. package/src/browser/react/location-state-shared.ts +166 -8
  89. package/src/browser/react/location-state.ts +39 -14
  90. package/src/browser/react/use-action.ts +6 -15
  91. package/src/browser/react/use-handle.ts +23 -69
  92. package/src/browser/react/use-link-status.ts +0 -4
  93. package/src/browser/react/use-navigation.ts +22 -5
  94. package/src/browser/react/use-params.ts +20 -10
  95. package/src/browser/react/use-reverse.ts +106 -0
  96. package/src/browser/react/use-router.ts +46 -11
  97. package/src/browser/react/use-search-params.ts +0 -5
  98. package/src/browser/react/use-segments.ts +11 -21
  99. package/src/browser/response-adapter.ts +52 -1
  100. package/src/browser/rsc-router.tsx +215 -76
  101. package/src/browser/scroll-restoration.ts +46 -39
  102. package/src/browser/segment-reconciler.ts +36 -9
  103. package/src/browser/segment-structure-assert.ts +2 -2
  104. package/src/browser/server-action-bridge.ts +176 -50
  105. package/src/browser/types.ts +95 -11
  106. package/src/browser/validate-redirect-origin.ts +43 -16
  107. package/src/build/collect-fallback-refs.ts +107 -0
  108. package/src/build/generate-manifest.ts +65 -40
  109. package/src/build/generate-route-types.ts +5 -0
  110. package/src/build/index.ts +8 -2
  111. package/src/build/prefix-tree-utils.ts +123 -0
  112. package/src/build/route-trie.ts +137 -32
  113. package/src/build/route-types/codegen.ts +4 -4
  114. package/src/build/route-types/include-resolution.ts +9 -2
  115. package/src/build/route-types/param-extraction.ts +6 -3
  116. package/src/build/route-types/per-module-writer.ts +7 -4
  117. package/src/build/route-types/router-processing.ts +278 -96
  118. package/src/build/route-types/scan-filter.ts +9 -2
  119. package/src/build/route-types/source-scan.ts +118 -0
  120. package/src/build/runtime-discovery.ts +9 -20
  121. package/src/cache/cache-error.ts +104 -0
  122. package/src/cache/cache-policy.ts +68 -28
  123. package/src/cache/cache-runtime.ts +149 -43
  124. package/src/cache/cache-scope.ts +148 -81
  125. package/src/cache/cache-tag.ts +98 -0
  126. package/src/cache/cf/cf-cache-store.ts +2550 -93
  127. package/src/cache/cf/index.ts +11 -17
  128. package/src/cache/document-cache.ts +78 -27
  129. package/src/cache/handle-snapshot.ts +63 -0
  130. package/src/cache/index.ts +23 -20
  131. package/src/cache/memory-segment-store.ts +136 -37
  132. package/src/cache/profile-registry.ts +6 -30
  133. package/src/cache/read-through-swr.ts +41 -11
  134. package/src/cache/segment-codec.ts +0 -16
  135. package/src/cache/tag-invalidation.ts +230 -0
  136. package/src/cache/taint.ts +55 -0
  137. package/src/cache/types.ts +33 -100
  138. package/src/cache/vercel/index.ts +11 -0
  139. package/src/cache/vercel/vercel-cache-store.ts +799 -0
  140. package/src/client.rsc.tsx +6 -21
  141. package/src/client.tsx +108 -290
  142. package/src/component-utils.ts +19 -0
  143. package/src/context-var.ts +84 -2
  144. package/src/debug.ts +2 -2
  145. package/src/decode-loader-results.ts +36 -0
  146. package/src/defer.ts +196 -0
  147. package/src/deps/ssr.ts +0 -1
  148. package/src/errors.ts +30 -4
  149. package/src/handle.ts +70 -22
  150. package/src/handles/MetaTags.tsx +0 -14
  151. package/src/handles/breadcrumbs.ts +16 -5
  152. package/src/handles/meta.ts +0 -39
  153. package/src/host/cookie-handler.ts +0 -36
  154. package/src/host/errors.ts +0 -24
  155. package/src/host/index.ts +8 -2
  156. package/src/host/pattern-matcher.ts +7 -50
  157. package/src/host/router.ts +107 -99
  158. package/src/host/testing.ts +40 -27
  159. package/src/host/types.ts +37 -4
  160. package/src/host/utils.ts +1 -1
  161. package/src/href-client.ts +137 -22
  162. package/src/index.rsc.ts +52 -26
  163. package/src/index.ts +100 -38
  164. package/src/internal-debug.ts +2 -4
  165. package/src/loader-store.ts +500 -0
  166. package/src/loader.rsc.ts +20 -13
  167. package/src/loader.ts +12 -11
  168. package/src/missing-id-error.ts +68 -0
  169. package/src/network-error-thrower.tsx +1 -6
  170. package/src/outlet-context.ts +1 -1
  171. package/src/outlet-provider.tsx +1 -5
  172. package/src/prerender/param-hash.ts +10 -11
  173. package/src/prerender/store.ts +37 -41
  174. package/src/prerender.ts +198 -82
  175. package/src/redirect-origin.ts +100 -0
  176. package/src/response-utils.ts +37 -0
  177. package/src/reverse.ts +65 -15
  178. package/src/root-error-boundary.tsx +1 -19
  179. package/src/route-content-wrapper.tsx +7 -72
  180. package/src/route-definition/dsl-helpers.ts +437 -274
  181. package/src/route-definition/helper-factories.ts +29 -139
  182. package/src/route-definition/helpers-types.ts +113 -37
  183. package/src/route-definition/index.ts +3 -0
  184. package/src/route-definition/redirect.ts +52 -10
  185. package/src/route-definition/resolve-handler-use.ts +161 -0
  186. package/src/route-definition/use-item-types.ts +32 -0
  187. package/src/route-map-builder.ts +7 -17
  188. package/src/route-types.ts +37 -41
  189. package/src/router/basename.ts +14 -0
  190. package/src/router/content-negotiation.ts +108 -9
  191. package/src/router/error-handling.ts +13 -17
  192. package/src/router/find-match.ts +45 -22
  193. package/src/router/handler-context.ts +83 -41
  194. package/src/router/intercept-resolution.ts +25 -23
  195. package/src/router/lazy-includes.ts +19 -53
  196. package/src/router/loader-resolution.ts +213 -30
  197. package/src/router/logging.ts +5 -8
  198. package/src/router/manifest.ts +49 -45
  199. package/src/router/match-api.ts +121 -205
  200. package/src/router/match-context.ts +0 -22
  201. package/src/router/match-handlers.ts +58 -58
  202. package/src/router/match-middleware/background-revalidation.ts +27 -6
  203. package/src/router/match-middleware/cache-lookup.ts +205 -249
  204. package/src/router/match-middleware/cache-store.ts +45 -32
  205. package/src/router/match-middleware/intercept-resolution.ts +8 -28
  206. package/src/router/match-middleware/segment-resolution.ts +52 -18
  207. package/src/router/match-pipelines.ts +1 -42
  208. package/src/router/match-result.ts +104 -40
  209. package/src/router/metrics.ts +5 -34
  210. package/src/router/middleware-types.ts +13 -142
  211. package/src/router/middleware.ts +173 -143
  212. package/src/router/navigation-snapshot.ts +131 -0
  213. package/src/router/params-util.ts +23 -0
  214. package/src/router/pattern-matching.ts +109 -63
  215. package/src/router/prerender-match.ts +192 -54
  216. package/src/router/preview-match.ts +32 -102
  217. package/src/router/request-classification.ts +276 -0
  218. package/src/router/revalidation.ts +63 -55
  219. package/src/router/route-snapshot.ts +244 -0
  220. package/src/router/router-context.ts +6 -28
  221. package/src/router/router-interfaces.ts +100 -35
  222. package/src/router/router-options.ts +91 -11
  223. package/src/router/router-registry.ts +2 -5
  224. package/src/router/segment-resolution/fresh.ts +242 -75
  225. package/src/router/segment-resolution/helpers.ts +64 -25
  226. package/src/router/segment-resolution/loader-cache.ts +41 -37
  227. package/src/router/segment-resolution/revalidation.ts +456 -372
  228. package/src/router/segment-resolution/static-store.ts +19 -5
  229. package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
  230. package/src/router/segment-resolution/view-transition-default.ts +36 -0
  231. package/src/router/segment-resolution.ts +4 -1
  232. package/src/router/segment-wrappers.ts +2 -3
  233. package/src/router/state-cookie-name.ts +33 -0
  234. package/src/router/substitute-pattern-params.ts +56 -0
  235. package/src/router/telemetry-otel.ts +0 -20
  236. package/src/router/telemetry.ts +96 -19
  237. package/src/router/timeout.ts +0 -20
  238. package/src/router/trie-matching.ts +91 -46
  239. package/src/router/types.ts +10 -63
  240. package/src/router/url-params.ts +44 -0
  241. package/src/router.ts +134 -43
  242. package/src/rsc/handler-context.ts +3 -2
  243. package/src/rsc/handler.ts +492 -383
  244. package/src/rsc/helpers.ts +162 -46
  245. package/src/rsc/index.ts +1 -1
  246. package/src/rsc/json-route-result.ts +38 -0
  247. package/src/rsc/loader-fetch.ts +23 -3
  248. package/src/rsc/manifest-init.ts +33 -42
  249. package/src/rsc/origin-guard.ts +39 -25
  250. package/src/rsc/progressive-enhancement.ts +30 -3
  251. package/src/rsc/redirect-guard.ts +99 -0
  252. package/src/rsc/response-error.ts +79 -12
  253. package/src/rsc/response-route-handler.ts +90 -63
  254. package/src/rsc/rsc-rendering.ts +56 -54
  255. package/src/rsc/runtime-warnings.ts +23 -10
  256. package/src/rsc/server-action.ts +74 -67
  257. package/src/rsc/ssr-setup.ts +18 -2
  258. package/src/rsc/types.ts +25 -6
  259. package/src/runtime-env.ts +18 -0
  260. package/src/search-params.ts +4 -20
  261. package/src/segment-content-promise.ts +67 -0
  262. package/src/segment-loader-promise.ts +134 -0
  263. package/src/segment-system.tsx +272 -129
  264. package/src/serialize.ts +243 -0
  265. package/src/server/context.ts +309 -61
  266. package/src/server/cookie-store.ts +80 -5
  267. package/src/server/handle-store.ts +26 -24
  268. package/src/server/loader-registry.ts +10 -28
  269. package/src/server/request-context.ts +348 -128
  270. package/src/ssr/index.tsx +23 -15
  271. package/src/static-handler.ts +27 -18
  272. package/src/testing/cache-status.ts +162 -0
  273. package/src/testing/collect-handle.ts +40 -0
  274. package/src/testing/dispatch.ts +618 -0
  275. package/src/testing/dom.entry.ts +22 -0
  276. package/src/testing/e2e/fixture.ts +188 -0
  277. package/src/testing/e2e/index.ts +128 -0
  278. package/src/testing/e2e/matchers.ts +35 -0
  279. package/src/testing/e2e/page-helpers.ts +272 -0
  280. package/src/testing/e2e/parity.ts +387 -0
  281. package/src/testing/e2e/server.ts +195 -0
  282. package/src/testing/flight-matchers.ts +97 -0
  283. package/src/testing/flight-normalize.ts +11 -0
  284. package/src/testing/flight-runtime.d.ts +57 -0
  285. package/src/testing/flight-tree.ts +682 -0
  286. package/src/testing/flight.entry.ts +52 -0
  287. package/src/testing/flight.ts +232 -0
  288. package/src/testing/generated-routes.ts +183 -0
  289. package/src/testing/index.ts +99 -0
  290. package/src/testing/internal/context.ts +348 -0
  291. package/src/testing/internal/flight-client-globals.ts +30 -0
  292. package/src/testing/internal/seed-vars.ts +54 -0
  293. package/src/testing/render-handler.ts +330 -0
  294. package/src/testing/render-route.tsx +566 -0
  295. package/src/testing/run-loader.ts +378 -0
  296. package/src/testing/run-middleware.ts +205 -0
  297. package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
  298. package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
  299. package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
  300. package/src/testing/vitest-stubs/version.ts +5 -0
  301. package/src/testing/vitest.ts +305 -0
  302. package/src/theme/ThemeProvider.tsx +0 -52
  303. package/src/theme/ThemeScript.tsx +0 -6
  304. package/src/theme/constants.ts +0 -12
  305. package/src/theme/index.ts +0 -7
  306. package/src/theme/theme-context.ts +1 -5
  307. package/src/theme/theme-script.ts +0 -14
  308. package/src/theme/use-theme.ts +0 -3
  309. package/src/types/boundaries.ts +0 -35
  310. package/src/types/cache-types.ts +17 -8
  311. package/src/types/error-types.ts +30 -90
  312. package/src/types/global-namespace.ts +54 -41
  313. package/src/types/handler-context.ts +233 -81
  314. package/src/types/index.ts +1 -10
  315. package/src/types/loader-types.ts +44 -15
  316. package/src/types/request-scope.ts +107 -0
  317. package/src/types/route-config.ts +6 -50
  318. package/src/types/route-entry.ts +19 -7
  319. package/src/types/segments.ts +37 -14
  320. package/src/urls/include-helper.ts +33 -70
  321. package/src/urls/index.ts +1 -11
  322. package/src/urls/path-helper-types.ts +58 -11
  323. package/src/urls/path-helper.ts +57 -111
  324. package/src/urls/pattern-types.ts +48 -19
  325. package/src/urls/response-types.ts +25 -22
  326. package/src/urls/type-extraction.ts +58 -139
  327. package/src/urls/urls-function.ts +1 -18
  328. package/src/use-loader.tsx +346 -89
  329. package/src/vite/debug.ts +185 -0
  330. package/src/vite/discovery/bundle-postprocess.ts +36 -38
  331. package/src/vite/discovery/discover-routers.ts +130 -85
  332. package/src/vite/discovery/discovery-errors.ts +194 -0
  333. package/src/vite/discovery/gate-state.ts +171 -0
  334. package/src/vite/discovery/prerender-collection.ts +192 -99
  335. package/src/vite/discovery/route-types-writer.ts +40 -84
  336. package/src/vite/discovery/self-gen-tracking.ts +27 -1
  337. package/src/vite/discovery/state.ts +51 -6
  338. package/src/vite/discovery/virtual-module-codegen.ts +14 -34
  339. package/src/vite/index.ts +8 -0
  340. package/src/vite/plugin-types.ts +187 -69
  341. package/src/vite/plugins/cjs-to-esm.ts +8 -18
  342. package/src/vite/plugins/client-ref-dedup.ts +16 -11
  343. package/src/vite/plugins/client-ref-hashing.ts +28 -15
  344. package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
  345. package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
  346. package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
  347. package/src/vite/plugins/expose-action-id.ts +49 -98
  348. package/src/vite/plugins/expose-id-utils.ts +11 -50
  349. package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
  350. package/src/vite/plugins/expose-ids/handler-transform.ts +10 -48
  351. package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
  352. package/src/vite/plugins/expose-ids/router-transform.ts +20 -16
  353. package/src/vite/plugins/expose-internal-ids.ts +554 -317
  354. package/src/vite/plugins/performance-tracks.ts +89 -0
  355. package/src/vite/plugins/refresh-cmd.ts +89 -27
  356. package/src/vite/plugins/use-cache-transform.ts +73 -83
  357. package/src/vite/plugins/vercel-output.ts +258 -0
  358. package/src/vite/plugins/version-injector.ts +21 -25
  359. package/src/vite/plugins/version-plugin.ts +41 -20
  360. package/src/vite/plugins/virtual-entries.ts +2 -17
  361. package/src/vite/rango.ts +257 -289
  362. package/src/vite/router-discovery.ts +930 -140
  363. package/src/vite/utils/ast-handler-extract.ts +15 -31
  364. package/src/vite/utils/banner.ts +4 -4
  365. package/src/vite/utils/bundle-analysis.ts +10 -15
  366. package/src/vite/utils/client-chunks.ts +184 -0
  367. package/src/vite/utils/forward-user-plugins.ts +171 -0
  368. package/src/vite/utils/manifest-utils.ts +4 -59
  369. package/src/vite/utils/package-resolution.ts +20 -52
  370. package/src/vite/utils/prerender-utils.ts +27 -29
  371. package/src/vite/utils/shared-utils.ts +92 -42
  372. package/src/browser/action-response-classifier.ts +0 -99
  373. package/src/browser/react/use-client-cache.ts +0 -58
  374. package/src/browser/shallow.ts +0 -40
  375. package/src/handles/index.ts +0 -7
  376. package/src/router/middleware-cookies.ts +0 -55
@@ -1,57 +1,29 @@
1
- /**
2
- * Package Resolution Utilities
3
- *
4
- * Handles detection of workspace vs npm install context and generates
5
- * appropriate aliases and exclude lists for Vite configuration.
6
- */
7
-
8
1
  import { existsSync } from "node:fs";
2
+ import { createRequire } from "node:module";
9
3
  import { resolve } from "node:path";
10
- import packageJson from "../../../package.json" with { type: "json" };
4
+ import packageJson from "../../../package.json";
5
+
6
+ const require = createRequire(import.meta.url);
11
7
 
12
8
  /**
13
9
  * The canonical name used in virtual entries (without scope)
14
10
  */
15
11
  const VIRTUAL_PACKAGE_NAME = "@rangojs/router";
16
12
 
17
- /**
18
- * Get the published package name (e.g., "@rangojs/router")
19
- */
20
13
  export function getPublishedPackageName(): string {
21
14
  return packageJson.name;
22
15
  }
23
16
 
24
- /**
25
- * Check if the package is installed from npm (scoped) vs workspace (unscoped)
26
- *
27
- * In workspace development:
28
- * - Package is installed as "@rangojs/router" via pnpm workspace alias
29
- * - The scoped name (@rangojs/router) doesn't exist in node_modules
30
- *
31
- * When installed from npm:
32
- * - Package is installed as "@rangojs/router"
33
- * - We need aliases to map "@rangojs/router/*" to "@rangojs/router/*"
34
- */
35
17
  export function isInstalledFromNpm(): boolean {
36
18
  const packageName = getPublishedPackageName();
37
19
  // Check if the scoped package exists in node_modules
38
20
  return existsSync(resolve(process.cwd(), "node_modules", packageName));
39
21
  }
40
22
 
41
- /**
42
- * Check if we're in a monorepo/workspace development context
43
- */
44
23
  export function isWorkspaceDevelopment(): boolean {
45
24
  return !isInstalledFromNpm();
46
25
  }
47
26
 
48
- /**
49
- * Subpaths derived from package.json exports that use TypeScript source.
50
- * These must be excluded from Vite's dependency optimization (they ship
51
- * as .ts/.tsx, not compiled JS) and aliased when installed from npm.
52
- *
53
- * Derived automatically from the exports field to prevent drift.
54
- */
55
27
  const SOURCE_EXPORT_SUBPATHS = Object.keys(packageJson.exports)
56
28
  .filter((key) => {
57
29
  const entry = (
@@ -67,12 +39,6 @@ const SOURCE_EXPORT_SUBPATHS = Object.keys(packageJson.exports)
67
39
  })
68
40
  .map((key) => key.replace(/^\./, ""));
69
41
 
70
- /**
71
- * Generate the list of modules to exclude from Vite's dependency optimization.
72
- *
73
- * We include both the published name and the virtual name because
74
- * Vite's optimizer runs before alias resolution.
75
- */
76
42
  export function getExcludeDeps(): string[] {
77
43
  const packageName = getPublishedPackageName();
78
44
  const excludes: string[] = [];
@@ -89,24 +55,10 @@ export function getExcludeDeps(): string[] {
89
55
  return excludes;
90
56
  }
91
57
 
92
- /**
93
- * Subpaths that need aliasing — same as SOURCE_EXPORT_SUBPATHS.
94
- * When installed from npm, virtual entries may use a different package name
95
- * than the published one; aliases bridge them.
96
- */
97
58
  const ALIAS_SUBPATHS = SOURCE_EXPORT_SUBPATHS;
98
59
 
99
- /**
100
- * Generate aliases to map virtual package paths to the actual published package.
101
- *
102
- * Only needed when installed from npm, where the package is under @rangojs/router
103
- * but virtual entries import from rsc-router/*.
104
- *
105
- * Returns empty object in workspace development where rsc-router resolves directly.
106
- */
107
60
  export function getPackageAliases(): Record<string, string> {
108
61
  if (isWorkspaceDevelopment()) {
109
- // No aliases needed - rsc-router resolves directly
110
62
  return {};
111
63
  }
112
64
 
@@ -119,3 +71,19 @@ export function getPackageAliases(): Record<string, string> {
119
71
 
120
72
  return aliases;
121
73
  }
74
+
75
+ export function getVendorAliases(): Record<string, string> {
76
+ const specs = [
77
+ "@vitejs/plugin-rsc/vendor/react-server-dom/client.edge",
78
+ "@vitejs/plugin-rsc/vendor/react-server-dom/server.edge",
79
+ ];
80
+ const aliases: Record<string, string> = {};
81
+ for (const spec of specs) {
82
+ try {
83
+ aliases[spec] = require.resolve(spec);
84
+ } catch {
85
+ // Non-fatal; Vite will warn if it cannot resolve the spec
86
+ }
87
+ }
88
+ return aliases;
89
+ }
@@ -9,18 +9,10 @@ import {
9
9
  } from "node:fs";
10
10
  import { resolve } from "node:path";
11
11
 
12
- /**
13
- * Escape special RegExp characters in a string for safe interpolation
14
- * into new RegExp() patterns.
15
- */
16
12
  export function escapeRegExp(str: string): string {
17
13
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18
14
  }
19
15
 
20
- /**
21
- * Encode route param values for path interpolation while preserving path
22
- * separators for wildcard params (splat-style values can include `/`).
23
- */
24
16
  export function encodePathParam(value: unknown): string {
25
17
  return String(value)
26
18
  .split("/")
@@ -28,31 +20,45 @@ export function encodePathParam(value: unknown): string {
28
20
  .join("/");
29
21
  }
30
22
 
31
- /**
32
- * Substitute route params into a pattern, stripping constraint and optional
33
- * syntax (:param(a|b)? -> value). Also handles wildcard params (*key).
34
- */
35
23
  export function substituteRouteParams(
36
24
  pattern: string,
37
25
  params: Record<string, string>,
38
26
  encode: (value: string) => string = encodeURIComponent,
39
27
  ): string {
40
28
  let result = pattern;
29
+ let hadOmittedOptional = false;
30
+
41
31
  for (const [key, value] of Object.entries(params)) {
42
32
  const escaped = escapeRegExp(key);
43
- result = result.replace(
44
- new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
45
- encode(value),
46
- );
47
- result = result.replace(`*${key}`, encode(value));
33
+ if (value === "") {
34
+ result = result.replace(
35
+ new RegExp(`:${escaped}(\\([^)]*\\))?(?!\\?)`),
36
+ "",
37
+ );
38
+ result = result.replace(`*${key}`, "");
39
+ } else {
40
+ result = result.replace(
41
+ new RegExp(`:${escaped}(\\([^)]*\\))?\\??`),
42
+ encode(value),
43
+ );
44
+ result = result.replace(`*${key}`, encode(value));
45
+ }
46
+ }
47
+
48
+ result = result.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)(\([^)]*\))?\?/g, () => {
49
+ hadOmittedOptional = true;
50
+ return "";
51
+ });
52
+
53
+ if (hadOmittedOptional) {
54
+ const hadTrailingSlash = pattern.length > 1 && pattern.endsWith("/");
55
+ result = result.replace(/\/\/+/g, "/").replace(/\/+$/, "") || "/";
56
+ if (hadTrailingSlash && !result.endsWith("/")) result += "/";
48
57
  }
58
+
49
59
  return result;
50
60
  }
51
61
 
52
- /**
53
- * Run an async function over items with bounded concurrency.
54
- * Errors propagate immediately and abort remaining work.
55
- */
56
62
  export async function runWithConcurrency<T>(
57
63
  items: T[],
58
64
  concurrency: number,
@@ -73,10 +79,6 @@ export async function runWithConcurrency<T>(
73
79
  await Promise.all(Array.from({ length: limit }, () => worker()));
74
80
  }
75
81
 
76
- /**
77
- * Group prerender entries by their concurrency setting so each group
78
- * can be rendered with the appropriate parallelism.
79
- */
80
82
  export function groupByConcurrency<T extends { concurrency: number }>(
81
83
  entries: T[],
82
84
  ): { concurrency: number; entries: T[] }[] {
@@ -96,10 +98,6 @@ export function groupByConcurrency<T extends { concurrency: number }>(
96
98
  }));
97
99
  }
98
100
 
99
- /**
100
- * Notify all routers' onError callbacks about a build-time error.
101
- * Uses a synthetic request since there is no real request during build.
102
- */
103
101
  export function notifyOnError(
104
102
  registry: Map<string, any>,
105
103
  error: unknown,
@@ -1,43 +1,57 @@
1
- import type { Plugin } from "vite";
1
+ import type { Plugin, ResolvedConfig } from "vite";
2
2
  import * as Vite from "vite";
3
3
  import { getPublishedPackageName } from "./package-resolution.js";
4
+ import { performanceTracksOptimizeDepsPlugin } from "../plugins/performance-tracks.js";
4
5
  import {
5
6
  VIRTUAL_ENTRY_BROWSER,
6
7
  VIRTUAL_ENTRY_SSR,
7
8
  getVirtualEntryRSC,
9
+ getVirtualVersionContent,
8
10
  VIRTUAL_IDS,
9
11
  } from "../plugins/virtual-entries.js";
10
12
 
13
+ // Cloudflare preset: @cloudflare/vite-plugin sets optimizeDeps.entries (string
14
+ // or array) on the rsc environment. Single source for both the discovery plugin
15
+ // and the version injector so they target the same entry.
16
+ export function resolveRscEntryFromConfig(
17
+ config: ResolvedConfig,
18
+ ): string | undefined {
19
+ const entries = (config.environments as any)?.["rsc"]?.optimizeDeps?.entries;
20
+ if (typeof entries === "string") return entries;
21
+ if (Array.isArray(entries) && entries.length > 0) return entries[0];
22
+ return undefined;
23
+ }
24
+
11
25
  /**
12
- * esbuild plugin to provide rsc-router:version virtual module during optimization.
13
- * This is needed because esbuild runs during Vite's dependency optimization phase,
14
- * before Vite's plugin system can handle virtual modules.
26
+ * Rolldown plugin to provide the version virtual module during dependency
27
+ * optimization. Vite 8 optimizes deps with Rolldown (a Rollup-style plugin
28
+ * pipeline that is separate from the main plugin set), so this is a
29
+ * resolveId/load plugin under optimizeDeps.rolldownOptions. Any dep pulled into
30
+ * optimization that imports the version virtual module gets a "dev" stub here;
31
+ * the real VERSION is injected into runtime modules by the version plugin.
15
32
  */
16
- const versionEsbuildPlugin = {
33
+ const versionRolldownPlugin = {
17
34
  name: "@rangojs/router-version",
18
- setup(build: any): void {
19
- build.onResolve({ filter: /^rsc-router:version$/ }, (args: any) => ({
20
- path: args.path,
21
- namespace: "@rangojs/router-virtual",
22
- }));
23
- build.onLoad(
24
- { filter: /.*/, namespace: "@rangojs/router-virtual" },
25
- () => ({
26
- contents: `export const VERSION = "dev";`,
27
- loader: "js",
28
- }),
29
- );
35
+ resolveId(id: string): string | undefined {
36
+ if (id === VIRTUAL_IDS.version) return "\0" + VIRTUAL_IDS.version;
37
+ return undefined;
38
+ },
39
+ load(id: string): string | undefined {
40
+ if (id === "\0" + VIRTUAL_IDS.version) {
41
+ return getVirtualVersionContent("dev");
42
+ }
43
+ return undefined;
30
44
  },
31
45
  };
32
46
 
33
47
  /**
34
- * Shared esbuild options for dependency optimization.
35
- * Includes the version stub plugin for all environments.
48
+ * Shared Rolldown options for dependency optimization (Vite 8).
49
+ * Includes the version stub plugin and the performance-tracks RSDW patch.
36
50
  */
37
- export const sharedEsbuildOptions: {
38
- plugins: (typeof versionEsbuildPlugin)[];
51
+ export const sharedRolldownOptions: {
52
+ plugins: any[];
39
53
  } = {
40
- plugins: [versionEsbuildPlugin],
54
+ plugins: [versionRolldownPlugin, performanceTracksOptimizeDepsPlugin()],
41
55
  };
42
56
 
43
57
  /**
@@ -102,14 +116,54 @@ export function createVirtualEntriesPlugin(
102
116
  };
103
117
  }
104
118
 
119
+ // Matches rollup's FILE_NAME_CONFLICT message and reports whether the colliding
120
+ // file is a content-hashed asset, e.g.
121
+ // The emitted file "assets/index-DlGNrvnU.css" overwrites a previously ...
122
+ // The emitted file "assets/inter-latin-Dx4kXJAl.woff2" overwrites a ...
123
+ // The match is UNANCHORED on purpose: by the time the warning reaches this user
124
+ // onwarn handler, Vite's logger has wrapped rollup's raw message with an ANSI
125
+ // color sequence and a "[CODE] " label, e.g.
126
+ // "[FILE_NAME_CONFLICT] The emitted file \"...\" overwrites ..."
127
+ // A "^The emitted file" anchor sits behind that prefix and never matches; and
128
+ // Vite also strips the JSON.stringify quotes rollup puts around the filename, so
129
+ // the match is UNANCHORED and quote-OPTIONAL ("?...?"?). The non-whitespace
130
+ // capture stops at the space before "overwrites" (Vite's unquoted display form)
131
+ // or the closing quote (raw rollup form); either way it carries no ANSI.
132
+ // A content-hashed name ends with a "-" separator + a Vite content hash. The
133
+ // hash is a FIXED-LENGTH base64url run ([A-Za-z0-9_-], default 8), so it can
134
+ // itself contain "-"/"_": it CANNOT be located by splitting on the last "-"
135
+ // (that lands inside the hash whenever it carries a dash, e.g. "...-Cabi7G8-" ->
136
+ // "" or "...-CkhJZR-_" -> "_", which let those conflicts leak). Instead take the
137
+ // trailing HASH_LEN chars and require the "-" separator right before them. The
138
+ // hash must hold an uppercase letter or digit (a real hash is never an
139
+ // all-lowercase word), so stable names like "assets/manifest.json" or
140
+ // "assets/loading-skeleton.css" still surface as potential genuine overwrites.
141
+ function isContentHashedAssetConflict(message: string | undefined): boolean {
142
+ if (!message) return false;
143
+ const match =
144
+ /The emitted file "?([^"\s]+)"? overwrites a previously emitted file/.exec(
145
+ message,
146
+ );
147
+ if (!match) return false;
148
+ const fileName = match[1];
149
+ const base = fileName.slice(fileName.lastIndexOf("/") + 1);
150
+ const dot = base.lastIndexOf(".");
151
+ if (dot <= 0) return false;
152
+ const stem = base.slice(0, dot);
153
+ // HASH_LEN tracks Vite's default [hash] width; bump it if an app sets a custom
154
+ // assetFileNames hash length.
155
+ const HASH_LEN = 8;
156
+ if (stem.length < HASH_LEN + 1 || stem[stem.length - HASH_LEN - 1] !== "-") {
157
+ return false;
158
+ }
159
+ const hash = stem.slice(-HASH_LEN);
160
+ return /^[A-Za-z0-9_-]+$/.test(hash) && /[A-Z0-9]/.test(hash);
161
+ }
162
+
105
163
  /**
106
- * Rollup onwarn handler that suppresses known harmless warnings:
107
- * - "use client" directives: handled by the RSC plugin, not relevant to Rollup
108
- * - sourcemap errors: caused by "use client" directive at line 1:0 confusing sourcemap resolution
109
- * - sourcemap incomplete: plugins that transform without generating sourcemaps (router + RSC plugin)
110
- * - dynamic/static mixed imports: expected for router internals (e.g. request-context, cache-scope)
111
- * - empty bundle: @vitejs/plugin-rsc scan build (step 1/5) produces an empty "index" chunk
112
- * because the RSC entry is fully externalized during client-reference analysis
164
+ * Suppress known harmless warnings: "use client" directives, sourcemap errors,
165
+ * mixed imports (expected for router internals), empty bundles, and content-hashed
166
+ * asset collisions from @vitejs/plugin-rsc copying RSC-env assets to the client bundle.
113
167
  */
114
168
  export function onwarn(
115
169
  warning: Vite.Rollup.RollupLog,
@@ -118,14 +172,17 @@ export function onwarn(
118
172
  if (
119
173
  warning.code === "MODULE_LEVEL_DIRECTIVE" ||
120
174
  warning.code === "SOURCEMAP_ERROR" ||
121
- warning.code === "EMPTY_BUNDLE"
175
+ warning.code === "EMPTY_BUNDLE" ||
176
+ warning.code === "INEFFECTIVE_DYNAMIC_IMPORT"
177
+ ) {
178
+ return;
179
+ }
180
+ if (
181
+ warning.code === "FILE_NAME_CONFLICT" &&
182
+ isContentHashedAssetConflict(warning.message)
122
183
  ) {
123
184
  return;
124
185
  }
125
- // @vitejs/plugin-rsc@0.5.14: rsc:virtual:vite-rsc/assets-manifest renderChunk
126
- // returns { code } without map, causing Rollup to warn about incorrect sourcemaps.
127
- // This is harmless (simple string replacement). Remove this suppression if a
128
- // future version of @vitejs/plugin-rsc fixes the missing sourcemap.
129
186
  if (warning.message?.includes("Sourcemap is likely to be incorrect")) {
130
187
  return;
131
188
  }
@@ -140,10 +197,6 @@ export function onwarn(
140
197
  defaultHandler(warning);
141
198
  }
142
199
 
143
- /**
144
- * Manual chunks configuration for client build.
145
- * Splits React and router packages into separate chunks for better caching.
146
- */
147
200
  export function getManualChunks(id: string): string | undefined {
148
201
  const normalized = Vite.normalizePath(id);
149
202
 
@@ -155,13 +208,10 @@ export function getManualChunks(id: string): string | undefined {
155
208
  ) {
156
209
  return "react";
157
210
  }
158
- // Use dynamic package name from package.json
159
- // Check both npm install path and workspace symlink resolved path
160
211
  const packageName = getPublishedPackageName();
161
212
  if (
162
213
  normalized.includes(`node_modules/${packageName}/`) ||
163
- normalized.includes("packages/rsc-router/") ||
164
- normalized.includes("packages/rangojs-router/")
214
+ /\/packages\/(rsc-router|rangojs-router)\/(src|dist)\//.test(normalized)
165
215
  ) {
166
216
  return "router";
167
217
  }
@@ -1,99 +0,0 @@
1
- /**
2
- * Discriminated union of post-reconciliation action response scenarios.
3
- *
4
- * Error and full-update-unsupported are handled inline in the bridge
5
- * before reconciliation. This classifier only runs for partial responses
6
- * that have been successfully reconciled.
7
- */
8
- export type ActionScenario =
9
- | {
10
- type: "navigated-away";
11
- historyKeyChanged: boolean;
12
- onInterceptRoute: boolean;
13
- }
14
- | { type: "hmr-missing" }
15
- | { type: "consolidation-needed"; segmentIds: string[] }
16
- | { type: "concurrent-skip"; otherFetchingCount: number }
17
- | { type: "normal" };
18
-
19
- /**
20
- * Pure data inputs for classifying a partial action response.
21
- * All values come from the bridge but no browser APIs or side effects.
22
- */
23
- export interface ClassifierInput {
24
- /** window.location.pathname captured at action start */
25
- actionStartPathname: string;
26
- /** window.location.pathname at classification time */
27
- currentPathname: string;
28
- /** window.history.state?.key captured at action start */
29
- actionStartLocationKey: string | undefined;
30
- /** window.history.state?.key at classification time */
31
- currentLocationKey: string | undefined;
32
- /** Number of segments after reconciliation */
33
- reconciledSegmentCount: number;
34
- /** Number of matched segment IDs from server */
35
- matchedCount: number;
36
- /** Segment IDs needing consolidation (from concurrent action tracking) */
37
- consolidationSegments: string[] | null;
38
- /** Number of other actions still in "fetching" phase */
39
- otherFetchingActionCount: number;
40
- /** Current intercept source URL (null when not on intercept route) */
41
- currentInterceptSource: string | null;
42
- }
43
-
44
- /**
45
- * Classify a partial action response into one of 5 post-reconciliation
46
- * scenarios.
47
- *
48
- * Called after error and full-update cases are handled inline by the bridge.
49
- * The classification order matches the priority chain:
50
- * 1. User navigated away during action
51
- * 2. HMR missing segments (fewer reconciled than matched)
52
- * 3. Consolidation needed (concurrent actions finished)
53
- * 4. Concurrent skip (other actions still fetching)
54
- * 5. Normal (single action, no issues)
55
- *
56
- * This is a pure function with no side effects - the bridge handles
57
- * all UI updates, store mutations, and network requests based on the
58
- * returned scenario.
59
- */
60
- export function classifyActionResponse(input: ClassifierInput): ActionScenario {
61
- // Check if user navigated away during the action
62
- const userNavigatedAway =
63
- input.currentPathname !== input.actionStartPathname ||
64
- input.currentLocationKey !== input.actionStartLocationKey;
65
-
66
- if (userNavigatedAway) {
67
- const historyKeyChanged =
68
- input.currentLocationKey !== input.actionStartLocationKey;
69
- return {
70
- type: "navigated-away",
71
- historyKeyChanged,
72
- onInterceptRoute: input.currentInterceptSource !== null,
73
- };
74
- }
75
-
76
- // HMR resilience: segments missing after reconciliation
77
- if (input.reconciledSegmentCount < input.matchedCount) {
78
- return { type: "hmr-missing" };
79
- }
80
-
81
- // Consolidation needed for concurrent actions
82
- if (input.consolidationSegments && input.consolidationSegments.length > 0) {
83
- return {
84
- type: "consolidation-needed",
85
- segmentIds: input.consolidationSegments,
86
- };
87
- }
88
-
89
- // Other actions still fetching - skip UI update
90
- if (input.otherFetchingActionCount > 0) {
91
- return {
92
- type: "concurrent-skip",
93
- otherFetchingCount: input.otherFetchingActionCount,
94
- };
95
- }
96
-
97
- // Normal single-action completion
98
- return { type: "normal" };
99
- }
@@ -1,58 +0,0 @@
1
- "use client";
2
-
3
- import { useContext, useCallback } from "react";
4
- import { NavigationStoreContext } from "./context.js";
5
-
6
- /**
7
- * Return type for useClientCache hook
8
- */
9
- export interface ClientCacheControls {
10
- /**
11
- * Clear the client-side navigation cache.
12
- * Call this after data changes that happen outside of server actions
13
- * (e.g., REST API calls, WebSocket updates, etc.)
14
- *
15
- * This will also broadcast to other tabs to clear their caches.
16
- */
17
- clear: () => void;
18
- }
19
-
20
- /**
21
- * Hook to access client-side cache controls
22
- *
23
- * Use this when you need to manually invalidate the navigation cache
24
- * after data changes that happen outside of server actions.
25
- *
26
- * Server actions automatically clear the cache, so you only need this for:
27
- * - REST API mutations
28
- * - WebSocket-driven updates
29
- * - Other non-RSC data changes
30
- *
31
- * @example
32
- * ```tsx
33
- * function DataEditor() {
34
- * const { clear } = useClientCache();
35
- *
36
- * async function handleSave() {
37
- * await fetch('/api/data', { method: 'POST', body: JSON.stringify(data) });
38
- * // Clear cache so back/forward navigation shows fresh data
39
- * clear();
40
- * }
41
- *
42
- * return <button onClick={handleSave}>Save</button>;
43
- * }
44
- * ```
45
- */
46
- export function useClientCache(): ClientCacheControls {
47
- const ctx = useContext(NavigationStoreContext);
48
-
49
- if (!ctx) {
50
- throw new Error("useClientCache must be used within NavigationProvider");
51
- }
52
-
53
- const clear = useCallback(() => {
54
- ctx.store.clearHistoryCache();
55
- }, [ctx]);
56
-
57
- return { clear };
58
- }
@@ -1,40 +0,0 @@
1
- /**
2
- * Shallow comparison utility for selector optimization
3
- *
4
- * Used by useNavigation hook to prevent unnecessary re-renders
5
- * when the selected value hasn't changed.
6
- *
7
- * @param a - First value
8
- * @param b - Second value
9
- * @returns true if values are shallowly equal
10
- */
11
- export function shallow<T>(a: T, b: T): boolean {
12
- // Same reference or primitive equality
13
- if (Object.is(a, b)) return true;
14
-
15
- // Different types or non-objects
16
- if (typeof a !== "object" || typeof b !== "object") return false;
17
-
18
- // Null checks
19
- if (a === null || b === null) return false;
20
-
21
- // Compare object keys
22
- const keysA = Object.keys(a);
23
- const keysB = Object.keys(b);
24
-
25
- if (keysA.length !== keysB.length) return false;
26
-
27
- // Check each key's value with Object.is
28
- for (const key of keysA) {
29
- if (
30
- !Object.is(
31
- (a as Record<string, unknown>)[key],
32
- (b as Record<string, unknown>)[key],
33
- )
34
- ) {
35
- return false;
36
- }
37
- }
38
-
39
- return true;
40
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * Built-in handles for rsc-router.
3
- */
4
-
5
- export { Meta } from "./meta.ts";
6
- export { MetaTags } from "./MetaTags.tsx";
7
- export { Breadcrumbs, type BreadcrumbItem } from "./breadcrumbs.ts";
@@ -1,55 +0,0 @@
1
- /**
2
- * Cookie Utilities
3
- *
4
- * Parsing and serialization for HTTP cookies used by middleware context.
5
- */
6
-
7
- import type { CookieOptions } from "./middleware-types.js";
8
-
9
- /**
10
- * Parse cookies from Cookie header
11
- */
12
- export function parseCookies(
13
- cookieHeader: string | null,
14
- ): Record<string, string> {
15
- if (!cookieHeader) return {};
16
-
17
- const cookies: Record<string, string> = {};
18
- const pairs = cookieHeader.split(";");
19
-
20
- for (const pair of pairs) {
21
- const [name, ...rest] = pair.trim().split("=");
22
- if (name) {
23
- const raw = rest.join("=");
24
- try {
25
- cookies[name] = decodeURIComponent(raw);
26
- } catch {
27
- // Malformed percent-encoded value (e.g. %zz) - fall back to raw value
28
- cookies[name] = raw;
29
- }
30
- }
31
- }
32
-
33
- return cookies;
34
- }
35
-
36
- /**
37
- * Serialize a cookie for Set-Cookie header
38
- */
39
- export function serializeCookie(
40
- name: string,
41
- value: string,
42
- options: CookieOptions = {},
43
- ): string {
44
- let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
45
-
46
- if (options.domain) cookie += `; Domain=${options.domain}`;
47
- if (options.path) cookie += `; Path=${options.path}`;
48
- if (options.maxAge !== undefined) cookie += `; Max-Age=${options.maxAge}`;
49
- if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
50
- if (options.httpOnly) cookie += "; HttpOnly";
51
- if (options.secure) cookie += "; Secure";
52
- if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;
53
-
54
- return cookie;
55
- }