@octanejs/remix-router 0.1.0 → 0.1.2

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 (46) hide show
  1. package/README.md +20 -6
  2. package/package.json +12 -7
  3. package/src/index.ts +16 -14
  4. package/src/lib/Await.tsrx +1 -1
  5. package/src/lib/DefaultErrorComponent.tsrx +3 -3
  6. package/src/lib/RenderErrorBoundary.tsrx +1 -1
  7. package/src/lib/actions.ts +1 -1
  8. package/src/lib/components/MemoryRouter.tsrx +1 -1
  9. package/src/lib/components/Navigate.ts +1 -1
  10. package/src/lib/components/Router.tsrx +1 -1
  11. package/src/lib/components/RouterProvider.tsrx +1 -1
  12. package/src/lib/components/Routes.tsrx +1 -1
  13. package/src/lib/components/routes-collector.ts +1 -8
  14. package/src/lib/components/utils.ts +4 -65
  15. package/src/lib/components/with-props.ts +1 -1
  16. package/src/lib/context.ts +2 -4
  17. package/src/lib/dom/Form.tsrx +1 -1
  18. package/src/lib/dom/Link.tsrx +1 -1
  19. package/src/lib/dom/NavLink.tsrx +1 -1
  20. package/src/lib/dom/dom.ts +1 -1
  21. package/src/lib/dom/hooks.ts +1 -1
  22. package/src/lib/dom/lib.ts +8 -7
  23. package/src/lib/dom/routers.tsrx +1 -1
  24. package/src/lib/dom/server.tsrx +6 -28
  25. package/src/lib/errors.ts +1 -1
  26. package/src/lib/hooks.ts +6 -16
  27. package/src/lib/href.ts +9 -4
  28. package/src/lib/router/history.ts +2 -2
  29. package/src/lib/router/instrumentation.ts +391 -187
  30. package/src/lib/router/links.ts +1 -1
  31. package/src/lib/router/router.ts +128 -78
  32. package/src/lib/router/server-runtime-types.ts +8 -11
  33. package/src/lib/router/url.ts +1 -1
  34. package/src/lib/router/utils.ts +107 -31
  35. package/src/lib/server-runtime/cookies.ts +7 -7
  36. package/src/lib/server-runtime/crypto.ts +2 -2
  37. package/src/lib/server-runtime/mode.ts +1 -1
  38. package/src/lib/server-runtime/sessions/cookieStorage.ts +1 -1
  39. package/src/lib/server-runtime/sessions/memoryStorage.ts +1 -1
  40. package/src/lib/server-runtime/sessions.ts +8 -5
  41. package/src/lib/server-runtime/warnings.ts +1 -1
  42. package/src/lib/types/future.ts +1 -7
  43. package/src/lib/types/params.ts +1 -1
  44. package/src/lib/types/register.ts +1 -1
  45. package/src/lib/types/route-module.ts +1 -1
  46. package/src/lib/types/utils.ts +1 -1
package/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  [react-router](https://reactrouter.com) for the [octane](https://github.com/octanejs/octane) UI framework.
4
4
 
5
- react-router v7 ships as a single package, so this port **vendors the
5
+ react-router v8 ships as a single package, so this port **vendors the
6
6
  framework-agnostic router core byte-close** (loaders, actions, redirects,
7
- matching, history — validated by 161 of upstream's own router unit tests
8
- running against the vendored copy) and transcribes the React layer onto
9
- octane's hooks. The shipped surface matches react-router 1:1 — existing code
7
+ matching, history — validated by 161 ported upstream router tests plus four
8
+ focused v8.2 regression pins) and transcribes the React layer onto octane's
9
+ hooks. The shipped runtime surface matches react-router 1:1 — existing code
10
10
  works by changing the import.
11
11
 
12
12
  **The port is complete — full export parity.** Data mode, declarative mode
@@ -59,11 +59,25 @@ function User() @{
59
59
  | `@octanejs/remix-router` | the vendored core surface (matchPath, redirect, data, …) + `createMemoryRouter`, `RouterProvider`, `Outlet`, `Await`, `Link`, `useLinkClickHandler`, the full read-hook family (`useLoaderData`, `useNavigate`, `useNavigation`, `useRouteError`, …), declarative mode (`MemoryRouter`, `Routes`/`Route`, `Navigate`, `createRoutesFromChildren`/`Elements`), the DOM layer (`createBrowserRouter`/`createHashRouter`, `BrowserRouter`/`HashRouter`/`unstable_HistoryRouter`, `NavLink`, `useSearchParams`), mutations (`Form`, `useSubmit`, `useFormAction`, `useFetcher`/`useFetchers`), guards/scroll (`useBlocker`, `ScrollRestoration`, …), static SSR (`StaticRouter`/`StaticRouterProvider`/`createStaticHandler`/`createStaticRouter`), and cookies/sessions (`createCookie`, `createCookieSessionStorage`, …) | full parity |
60
60
  | `@octanejs/remix-router/dom` | `RouterProvider` with octane's `flushSync` wired in | mirror of `react-router/dom` |
61
61
 
62
+ ## React Router 8 migration
63
+
64
+ - React Router 8 no longer publishes a `react-router-dom` package. Import
65
+ everything from `@octanejs/remix-router`, except the flushSync-enabled
66
+ `RouterProvider`, which comes from `@octanejs/remix-router/dom`.
67
+ - Middleware is always enabled. Loader, action, and middleware `context` is a
68
+ `RouterContextProvider`; the `future.v8_middleware`,
69
+ `future.v8_passThroughRequests`, and
70
+ `future.v8_trailingSlashAwareDataRequests` flags are gone.
71
+ - The internal `hasErrorBoundary` route property is gone. Use `ErrorBoundary`
72
+ or `errorElement`.
73
+ - The package follows Octane's repository-wide Node.js 22 or newer runtime
74
+ contract.
75
+
62
76
  ## How it works
63
77
 
64
78
  - The router core under `src/lib/router/` is vendored verbatim from
65
- react-router 7.18.1 (`scripts/vendor-remix-router.mjs`; two documented
66
- type-only deviations; hand-edits prohibited).
79
+ react-router 8.2.0 (`scripts/vendor-remix-router.mjs`; two documented
80
+ Octane integration deviations; hand-edits prohibited).
67
81
  - `RouterProvider` preserves upstream's exact commit paths — `startTransition`
68
82
  wrapping, the `flushSync` option, and the ViewTransition dance (dormant until
69
83
  Phase E) — on octane's `useState`/`useLayoutEffect`/`useOptimistic`/
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@octanejs/remix-router",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
6
9
  "octane": {
7
10
  "hookSlots": {
8
11
  "manual": [
@@ -10,7 +13,7 @@
10
13
  ]
11
14
  }
12
15
  },
13
- "description": "react-router for the octane renderer — the framework-agnostic router core vendored byte-close from react-router v7, with the React layer (RouterProvider, hooks, Link, boundaries) transcribed onto octane.",
16
+ "description": "react-router for the octane renderer — the framework-agnostic router core vendored byte-close from react-router v8, with the React layer (RouterProvider, hooks, Link, boundaries) transcribed onto octane.",
14
17
  "author": {
15
18
  "name": "Dominic Gannaway",
16
19
  "email": "dg@domgan.com"
@@ -35,17 +38,19 @@
35
38
  "./dom": "./src/dom.ts"
36
39
  },
37
40
  "dependencies": {
38
- "cookie": "^1.0.1",
39
- "octane": "0.1.4"
41
+ "cookie-es": "^3.1.1"
42
+ },
43
+ "peerDependencies": {
44
+ "octane": "0.1.6"
40
45
  },
41
46
  "devDependencies": {
42
47
  "@tsrx/react": "^0.2.37",
43
48
  "esbuild": "^0.28.1",
44
49
  "react": "^19.2.0",
45
50
  "react-dom": "^19.2.0",
46
- "react-router": "7.18.1",
47
- "react-router-dom": "7.18.1",
48
- "vitest": "^4.1.9"
51
+ "react-router": "8.2.0",
52
+ "vitest": "^4.1.9",
53
+ "octane": "0.1.6"
49
54
  },
50
55
  "scripts": {
51
56
  "test": "vitest run"
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // @octanejs/remix-router — react-router for the octane renderer.
2
2
  //
3
- // react-router v7 ships as a single package whose framework-agnostic core has
3
+ // react-router v8 ships as a single package whose framework-agnostic core has
4
4
  // no runtime subpath, so the core (lib/router/* + framework-free lib helpers)
5
5
  // is VENDORED byte-close (see scripts/vendor-remix-router.mjs) and only the
6
6
  // React layer is transcribed onto octane's hooks. This entry mirrors upstream
@@ -24,8 +24,15 @@ export type {
24
24
  InstrumentRouterFunction,
25
25
  InstrumentRouteFunction,
26
26
  InstrumentationHandlerResult,
27
+ InstrumentationClientRouterResult,
28
+ InstrumentationServerHandlerResult,
27
29
  } from './lib/router/instrumentation';
28
- export { IDLE_NAVIGATION, IDLE_FETCHER, IDLE_BLOCKER } from './lib/router/router';
30
+ export {
31
+ createStaticHandler,
32
+ IDLE_NAVIGATION,
33
+ IDLE_FETCHER,
34
+ IDLE_BLOCKER,
35
+ } from './lib/router/router';
29
36
  export {
30
37
  data,
31
38
  generatePath,
@@ -179,12 +186,7 @@ export type {
179
186
  FetcherWithComponents,
180
187
  } from './lib/dom/lib';
181
188
  export { Form } from './lib/dom/Form.tsrx';
182
- export {
183
- StaticRouter,
184
- StaticRouterProvider,
185
- createStaticHandler,
186
- createStaticRouter,
187
- } from './lib/dom/server.tsrx';
189
+ export { StaticRouter, StaticRouterProvider, createStaticRouter } from './lib/dom/server.tsrx';
188
190
 
189
191
  // ── UNSAFE_ surface (shipped subset) ────────────────────────────────────────
190
192
  export {
@@ -194,7 +196,10 @@ export {
194
196
  invariant as UNSAFE_invariant,
195
197
  } from './lib/router/history';
196
198
  export { createRouter as UNSAFE_createRouter } from './lib/router/router';
197
- export { ErrorResponseImpl as UNSAFE_ErrorResponseImpl } from './lib/router/utils';
199
+ export {
200
+ defaultMapRouteProperties as UNSAFE_defaultMapRouteProperties,
201
+ ErrorResponseImpl as UNSAFE_ErrorResponseImpl,
202
+ } from './lib/router/utils';
198
203
  export {
199
204
  DataRouterContext as UNSAFE_DataRouterContext,
200
205
  DataRouterStateContext as UNSAFE_DataRouterStateContext,
@@ -204,10 +209,7 @@ export {
204
209
  RouteContext as UNSAFE_RouteContext,
205
210
  ViewTransitionContext as UNSAFE_ViewTransitionContext,
206
211
  } from './lib/context';
207
- export {
208
- hydrationRouteProperties as UNSAFE_hydrationRouteProperties,
209
- mapRouteProperties as UNSAFE_mapRouteProperties,
210
- } from './lib/components/utils';
212
+ export { hydrationRouteProperties as UNSAFE_hydrationRouteProperties } from './lib/components/utils';
211
213
  export {
212
214
  WithComponentProps as UNSAFE_WithComponentProps,
213
215
  withComponentProps as UNSAFE_withComponentProps,
@@ -217,7 +219,7 @@ export {
217
219
  withErrorBoundaryProps as UNSAFE_withErrorBoundaryProps,
218
220
  } from './lib/components/with-props';
219
221
  export type { Register } from './lib/types/register';
220
- export type { MiddlewareEnabled as UNSAFE_MiddlewareEnabled } from './lib/types/future';
222
+ export type { Future } from './lib/types/future';
221
223
 
222
224
  // ── Server runtime (vendored cookie/session surface) ────────────────────────
223
225
  export { createCookie, isCookie } from './lib/server-runtime/cookies';
@@ -1,4 +1,4 @@
1
- // Await — port of react-router@7.18.1 lib/components.tsx's Await +
1
+ // Await — port of react-router@8.2.0 lib/components.tsx's Await +
2
2
  // AwaitErrorBoundary + ResolveAwait onto octane. The class boundary becomes an
3
3
  // octane @try/@catch; the "throw to the suspense boundary" becomes use(promise)
4
4
  // (octane's suspend primitive); the TrackedPromise decoration (_tracked/_data/
@@ -1,9 +1,9 @@
1
- // DefaultErrorComponent — port of react-router@7.18.1 lib/hooks.tsx's default
1
+ // DefaultErrorComponent — port of react-router@8.2.0 lib/hooks.tsx's default
2
2
  // error UI. Markup-identical (differential fixtures still avoid it — the dev
3
3
  // stack trace can never byte-match across runtimes).
4
4
  import { useContext } from 'octane';
5
- import { RouteErrorContext, ENABLE_DEV_WARNINGS } from './context.ts';
6
- import { isRouteErrorResponse } from './router/utils.ts';
5
+ import { RouteErrorContext } from './context.ts';
6
+ import { ENABLE_DEV_WARNINGS, isRouteErrorResponse } from './router/utils.ts';
7
7
 
8
8
  export function DefaultErrorComponent() @{
9
9
  const error = useContext(RouteErrorContext);
@@ -1,4 +1,4 @@
1
- // RenderErrorBoundary — port of the class boundary in react-router@7.18.1
1
+ // RenderErrorBoundary — port of the class boundary in react-router@8.2.0
2
2
  // lib/hooks.tsx onto octane's @try/@catch (octane has no class components).
3
3
  // RSC digest branches are dropped (RSCRouterContext is hardwired false here).
4
4
  //
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/actions.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/actions.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  export function throwIfPotentialCSRFAttack(
4
4
  request: Request,
@@ -1,4 +1,4 @@
1
- // MemoryRouter — transcribed from react-router@7.18.1 lib/components.tsx.
1
+ // MemoryRouter — transcribed from react-router@8.2.0 lib/components.tsx.
2
2
  // A declarative Router over an in-memory history stack.
3
3
  import { startTransition, useCallback, useLayoutEffect, useRef, useState } from 'octane';
4
4
  import { createMemoryHistory } from '../router/history.ts';
@@ -1,4 +1,4 @@
1
- // Navigate — transcribed from react-router@7.18.1 lib/components.tsx.
1
+ // Navigate — transcribed from react-router@8.2.0 lib/components.tsx.
2
2
  // Renders nothing; navigates from an effect on mount/update. Plain .ts (no
3
3
  // JSX needed); the hooks it composes handle a slotless caller via bare-tag
4
4
  // sub-slots.
@@ -1,4 +1,4 @@
1
- // Router — transcribed from react-router@7.18.1 lib/components.tsx. The
1
+ // Router — transcribed from react-router@8.2.0 lib/components.tsx. The
2
2
  // low-level context provider every router variant renders through.
3
3
  import { useMemo } from 'octane';
4
4
  import { LocationContext, NavigationContext } from '../context.ts';
@@ -1,4 +1,4 @@
1
- // RouterProvider + DataRoutes + Outlet — transcribed from react-router@7.18.1
1
+ // RouterProvider + DataRoutes + Outlet — transcribed from react-router@8.2.0
2
2
  // lib/components.tsx onto octane. Structure preserved verbatim: useState for
3
3
  // router state + layout-effect subscription (early enough for render-driven
4
4
  // redirects; subscribe() replays a pre-attach notification), useOptimistic for
@@ -1,4 +1,4 @@
1
- // Routes — transcribed from react-router@7.18.1 lib/components.tsx, hybrid
1
+ // Routes — transcribed from react-router@8.2.0 lib/components.tsx, hybrid
2
2
  // per docs/remix-router-port-plan.md §2a:
3
3
  // - descriptor children (createRoutesFromElements results, `{expr}` arrays,
4
4
  // prop-position elements) go through createRoutesFromChildren verbatim;
@@ -1,5 +1,5 @@
1
1
  // Declarative `<Routes>`/`<Route>` support — transcribed from
2
- // react-router@7.18.1 lib/components.tsx with ONE octane-specific mechanism.
2
+ // react-router@8.2.0 lib/components.tsx with ONE octane-specific mechanism.
3
3
  //
4
4
  // Upstream walks React children (`createRoutesFromChildren`) reading
5
5
  // `element.type === Route`. Octane value-position JSX (argument position, prop
@@ -60,7 +60,6 @@ const ROUTE_PROP_KEYS = [
60
60
  'HydrateFallback',
61
61
  'errorElement',
62
62
  'ErrorBoundary',
63
- 'hasErrorBoundary',
64
63
  'shouldRevalidate',
65
64
  'handle',
66
65
  'lazy',
@@ -170,8 +169,6 @@ function buildRoute(entry: CollectorEntry, treePath: number[]): RouteObject {
170
169
  HydrateFallback: p.HydrateFallback,
171
170
  errorElement: p.errorElement,
172
171
  ErrorBoundary: p.ErrorBoundary,
173
- hasErrorBoundary:
174
- p.hasErrorBoundary === true || p.ErrorBoundary != null || p.errorElement != null,
175
172
  shouldRevalidate: p.shouldRevalidate,
176
173
  handle: p.handle,
177
174
  lazy: p.lazy,
@@ -295,10 +292,6 @@ export function createRoutesFromChildren(
295
292
  HydrateFallback: element.props.HydrateFallback,
296
293
  errorElement: element.props.errorElement,
297
294
  ErrorBoundary: element.props.ErrorBoundary,
298
- hasErrorBoundary:
299
- element.props.hasErrorBoundary === true ||
300
- element.props.ErrorBoundary != null ||
301
- element.props.errorElement != null,
302
295
  shouldRevalidate: element.props.shouldRevalidate,
303
296
  handle: element.props.handle,
304
297
  lazy: element.props.lazy,
@@ -1,16 +1,14 @@
1
- // Transcribed from react-router@7.18.1 lib/components.tsx (the non-component
2
- // utilities) onto octane: mapRouteProperties / hydrationRouteProperties /
1
+ // Transcribed from react-router@8.2.0 lib/components.tsx (the non-component
2
+ // utilities) onto octane: hydrationRouteProperties /
3
3
  // createMemoryRouter / Deferred / getOptimisticRouterState, plus warnOnce
4
4
  // (upstream imports it from lib/server-runtime/warnings.ts — inlined here,
5
5
  // the server runtime is out of scope).
6
- import { createElement } from 'octane';
7
6
  import type { InitialEntry } from '../router/history';
8
7
  import { createMemoryHistory } from '../router/history';
9
- import { warning } from '../router/history';
10
8
  import type { Router as DataRouter, RouterState } from '../router/router';
11
9
  import { createRouter } from '../router/router';
12
10
  import type { RouteMatch, RouteObject } from '../router/utils';
13
- import { ENABLE_DEV_WARNINGS } from '../context';
11
+ import { defaultMapRouteProperties } from '../router/utils';
14
12
  import { _renderMatches } from '../hooks';
15
13
 
16
14
  /**
@@ -29,65 +27,6 @@ export function warnOnce(condition: boolean, message: string): void {
29
27
  }
30
28
  }
31
29
 
32
- export function mapRouteProperties(route: RouteObject) {
33
- let updates: Partial<RouteObject> & { hasErrorBoundary: boolean } = {
34
- // Note: this check also occurs in createRoutesFromChildren so update
35
- // there if you change this -- please and thank you!
36
- hasErrorBoundary:
37
- route.hasErrorBoundary || route.ErrorBoundary != null || route.errorElement != null,
38
- };
39
-
40
- if (route.Component) {
41
- if (ENABLE_DEV_WARNINGS) {
42
- if (route.element) {
43
- warning(
44
- false,
45
- 'You should not include both `Component` and `element` on your route - ' +
46
- '`Component` will be used.',
47
- );
48
- }
49
- }
50
- Object.assign(updates, {
51
- element: createElement(route.Component as any),
52
- Component: undefined,
53
- });
54
- }
55
-
56
- if (route.HydrateFallback) {
57
- if (ENABLE_DEV_WARNINGS) {
58
- if (route.hydrateFallbackElement) {
59
- warning(
60
- false,
61
- 'You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - ' +
62
- '`HydrateFallback` will be used.',
63
- );
64
- }
65
- }
66
- Object.assign(updates, {
67
- hydrateFallbackElement: createElement(route.HydrateFallback as any),
68
- HydrateFallback: undefined,
69
- });
70
- }
71
-
72
- if (route.ErrorBoundary) {
73
- if (ENABLE_DEV_WARNINGS) {
74
- if (route.errorElement) {
75
- warning(
76
- false,
77
- 'You should not include both `ErrorBoundary` and `errorElement` on your route - ' +
78
- '`ErrorBoundary` will be used.',
79
- );
80
- }
81
- }
82
- Object.assign(updates, {
83
- errorElement: createElement(route.ErrorBoundary as any),
84
- ErrorBoundary: undefined,
85
- });
86
- }
87
-
88
- return updates;
89
- }
90
-
91
30
  export const hydrationRouteProperties: (keyof RouteObject)[] = [
92
31
  'HydrateFallback',
93
32
  'hydrateFallbackElement',
@@ -117,7 +56,7 @@ export function createMemoryRouter(routes: RouteObject[], opts?: MemoryRouterOpt
117
56
  hydrationData: opts?.hydrationData,
118
57
  routes,
119
58
  hydrationRouteProperties,
120
- mapRouteProperties,
59
+ mapRouteProperties: defaultMapRouteProperties,
121
60
  dataStrategy: opts?.dataStrategy,
122
61
  patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
123
62
  instrumentations: opts?.instrumentations,
@@ -1,4 +1,4 @@
1
- // UNSAFE_With*Props wrappers — transcribed from react-router@7.18.1
1
+ // UNSAFE_With*Props wrappers — transcribed from react-router@8.2.0
2
2
  // lib/components.tsx. Used by framework-mode codegen upstream; exported here
3
3
  // for surface parity. Plain .ts: cloneElement/createElement over descriptors.
4
4
  import { cloneElement, createElement } from 'octane';
@@ -1,4 +1,4 @@
1
- // Transcribed from react-router@7.18.1 lib/context.ts onto octane. The ten
1
+ // Transcribed from react-router@8.2.0 lib/context.ts onto octane. The ten
2
2
  // contexts and their shapes are verbatim; octane substitutions: createContext/
3
3
  // createElement from 'octane', `__DEV__` → NODE_ENV, no displayName (octane
4
4
  // contexts carry none). RSCRouterContext is kept (hardwired default false — no
@@ -48,7 +48,7 @@ export const ViewTransitionContext = createContext<ViewTransitionContextObject>(
48
48
  isTransitioning: false,
49
49
  });
50
50
 
51
- // TODO: (v7) Change the useFetcher data from `any` to `unknown`
51
+ // TODO: (v9) Change the useFetcher data from `any` to `unknown`
52
52
  export type FetchersContextObject = Map<string, any>;
53
53
 
54
54
  export const FetchersContext = createContext<FetchersContextObject>(new Map());
@@ -125,5 +125,3 @@ export const RouteContext = createContext<RouteContextObject>({
125
125
  });
126
126
 
127
127
  export const RouteErrorContext = createContext<any>(null);
128
-
129
- export const ENABLE_DEV_WARNINGS = process.env.NODE_ENV !== 'production';
@@ -1,4 +1,4 @@
1
- // Form — transcribed from react-router@7.18.1 lib/dom/lib.tsx onto octane.
1
+ // Form — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto octane.
2
2
  // forwardRef → ref-as-prop. The submit handler is a NATIVE delegated `submit`
3
3
  // listener (octane has no synthetic events): `event.submitter` is read
4
4
  // directly off the native SubmitEvent where React goes through
@@ -1,4 +1,4 @@
1
- // Link — transcribed from react-router@7.18.1 lib/dom/lib.tsx onto octane.
1
+ // Link — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto octane.
2
2
  // forwardRef → ref-as-prop (octane refs are props; documented divergence).
3
3
  // Framework-mode prefetching (usePrefetchBehavior / PrefetchPageLinks) is
4
4
  // inert outside a FrameworkContext upstream and is dropped here — the
@@ -1,4 +1,4 @@
1
- // NavLink — transcribed from react-router@7.18.1 lib/dom/lib.tsx onto octane.
1
+ // NavLink — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto octane.
2
2
  // forwardRef → ref-as-prop. Renders <Link> with active/pending-derived
3
3
  // className/style/aria-current; `className`, `style`, and `children` accept
4
4
  // render props receiving { isActive, isPending, isTransitioning }. Octane
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/dom/dom.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/dom/dom.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import { warning } from '../router/history';
4
4
  import type { RelativeRoutingType } from '../router/router';
@@ -1,4 +1,4 @@
1
- // DOM hooks — transcribed from react-router@7.18.1 lib/dom/lib.tsx onto
1
+ // DOM hooks — transcribed from react-router@8.2.0 lib/dom/lib.tsx onto
2
2
  // octane. This PR ships useLinkClickHandler (Link's engine); the remaining DOM
3
3
  // hooks (useSearchParams, useSubmit, useFetcher, …) land in later phases per
4
4
  // docs/remix-router-port-plan.md.
@@ -1,4 +1,4 @@
1
- // DOM-mode entry points + hooks — transcribed from react-router@7.18.1
1
+ // DOM-mode entry points + hooks — transcribed from react-router@8.2.0
2
2
  // lib/dom/lib.tsx onto octane: createBrowserRouter / createHashRouter (with
3
3
  // upstream's __staticRouterHydrationData parsing + error deserialization),
4
4
  // useSearchParams, and useViewTransitionState (needed internally by NavLink;
@@ -38,11 +38,12 @@ import type { RouteObject } from '../router/utils';
38
38
  import {
39
39
  ErrorResponseImpl,
40
40
  SUPPORTED_ERROR_TYPES,
41
+ defaultMapRouteProperties,
41
42
  joinPaths,
42
43
  matchPath,
43
44
  stripBasename,
44
45
  } from '../router/utils';
45
- import { hydrationRouteProperties, mapRouteProperties } from '../components/utils';
46
+ import { hydrationRouteProperties } from '../components/utils';
46
47
  import {
47
48
  useBlocker,
48
49
  useLocation,
@@ -81,7 +82,7 @@ export function createBrowserRouter(routes: RouteObject[], opts?: DOMRouterOpts)
81
82
  history: createBrowserHistory({ window: opts?.window }),
82
83
  hydrationData: opts?.hydrationData || parseHydrationData(),
83
84
  routes,
84
- mapRouteProperties,
85
+ mapRouteProperties: defaultMapRouteProperties,
85
86
  hydrationRouteProperties,
86
87
  dataStrategy: opts?.dataStrategy,
87
88
  patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
@@ -102,7 +103,7 @@ export function createHashRouter(routes: RouteObject[], opts?: DOMRouterOpts): D
102
103
  history: createHashHistory({ window: opts?.window }),
103
104
  hydrationData: opts?.hydrationData || parseHydrationData(),
104
105
  routes,
105
- mapRouteProperties,
106
+ mapRouteProperties: defaultMapRouteProperties,
106
107
  hydrationRouteProperties,
107
108
  dataStrategy: opts?.dataStrategy,
108
109
  patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
@@ -134,7 +135,7 @@ function deserializeErrors(errors: DataRouter['state']['errors']): DataRouter['s
134
135
  let serialized: DataRouter['state']['errors'] = {};
135
136
  for (let [key, val] of entries) {
136
137
  // Hey you! If you change this, please change the corresponding logic in
137
- // serializeErrors in react-router-dom/server.tsx :)
138
+ // serializeErrors in lib/dom/server.tsx :)
138
139
  if (val && val.__type === 'RouteErrorResponse') {
139
140
  serialized[key] = new ErrorResponseImpl(
140
141
  val.status,
@@ -246,7 +247,7 @@ export function useViewTransitionState(to: To, ...args: any[]): boolean {
246
247
 
247
248
  invariant(
248
249
  vtContext != null,
249
- "`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. " +
250
+ "`useViewTransitionState` must be used within `react-router/dom`'s `RouterProvider`. " +
250
251
  'Did you accidentally import `RouterProvider` from `react-router`?',
251
252
  );
252
253
 
@@ -276,7 +277,7 @@ export function useViewTransitionState(to: To, ...args: any[]): boolean {
276
277
 
277
278
  // ── Phase D — mutations ─────────────────────────────────────────────────────
278
279
  // useSubmit / useFormAction / useFetcher / useFetchers — transcribed from
279
- // react-router@7.18.1 lib/dom/lib.tsx. The dom-side data-router guards mirror
280
+ // react-router@8.2.0 lib/dom/lib.tsx. The dom-side data-router guards mirror
280
281
  // upstream's local DataRouterHook enum + console errors.
281
282
 
282
283
  enum DataRouterHook {
@@ -1,5 +1,5 @@
1
1
  // BrowserRouter / HashRouter / HistoryRouter — transcribed from
2
- // react-router@7.18.1 lib/dom/lib.tsx. Declarative routers over browser /
2
+ // react-router@8.2.0 lib/dom/lib.tsx. Declarative routers over browser /
3
3
  // hash / caller-provided history (upstream repeats the subscribe body in each;
4
4
  // so does this transcription).
5
5
  import { startTransition, useCallback, useLayoutEffect, useRef, useState } from 'octane';
@@ -1,22 +1,15 @@
1
- // Static SSR — transcribed from react-router@7.18.1 lib/dom/server.tsx onto
1
+ // Static SSR — transcribed from react-router@8.2.0 lib/dom/server.tsx onto
2
2
  // octane: StaticRouter (a Router that may not navigate), StaticRouterProvider
3
3
  // (renders a static data router + the __staticRouterHydrationData script),
4
- // createStaticHandler (the dom wrapper adding mapRouteProperties), and
5
- // createStaticRouter (a stateless DataRouter over a StaticHandlerContext).
4
+ // and createStaticRouter (a stateless DataRouter over a StaticHandlerContext).
6
5
  // Render through `octane/server` (renderToString / renderToPipeableStream).
7
6
  import type { Location, Path, To } from '../router/history.ts';
8
7
  import { Action as NavigationType, createPath, invariant, parsePath } from '../router/history.ts';
9
- import {
10
- IDLE_BLOCKER,
11
- IDLE_FETCHER,
12
- IDLE_NAVIGATION,
13
- createStaticHandler as routerCreateStaticHandler,
14
- } from '../router/router.ts';
8
+ import { IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION } from '../router/router.ts';
15
9
  import { convertRoutesToDataRoutes, isRouteErrorResponse } from '../router/utils.ts';
16
10
  import { ABSOLUTE_URL_REGEX } from '../router/url.ts';
17
11
  import { Router } from '../components/Router.tsrx';
18
12
  import { DataRoutes } from '../components/RouterProvider.tsrx';
19
- import { mapRouteProperties } from '../components/utils.ts';
20
13
  import {
21
14
  DataRouterContext,
22
15
  DataRouterStateContext,
@@ -136,7 +129,7 @@ function serializeErrors(errors) {
136
129
  const serialized = {};
137
130
  for (const [key, val] of entries) {
138
131
  // Hey you! If you change this, please change the corresponding logic in
139
- // deserializeErrors in react-router-dom/index.tsx :)
132
+ // deserializeErrors in lib/dom/lib.tsx :)
140
133
  if (isRouteErrorResponse(val)) {
141
134
  serialized[key] = { ...val, __type: 'RouteErrorResponse' };
142
135
  } else if (val instanceof Error) {
@@ -190,22 +183,12 @@ function getStatelessNavigator() {
190
183
  };
191
184
  }
192
185
 
193
- /**
194
- * Create a static handler to perform server-side data loading.
195
- */
196
- export function createStaticHandler(routes, opts) {
197
- return routerCreateStaticHandler(routes, {
198
- ...opts,
199
- mapRouteProperties,
200
- });
201
- }
202
-
203
186
  /**
204
187
  * Create a static DataRouter for server-side rendering.
205
188
  */
206
189
  export function createStaticRouter(routes, context, opts = {}) {
207
190
  const manifest = {};
208
- const dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, undefined, manifest);
191
+ const dataRoutes = convertRoutesToDataRoutes(routes, undefined, undefined, manifest);
209
192
 
210
193
  // Because our context matches may be from a set of routes passed to
211
194
  // createStaticHandler(), we update them here with our newly created/enhanced
@@ -226,12 +209,7 @@ export function createStaticRouter(routes, context, opts = {}) {
226
209
  return context.basename;
227
210
  },
228
211
  get future() {
229
- return {
230
- v8_middleware: false,
231
- v8_passThroughRequests: false,
232
- v8_trailingSlashAwareDataRequests: false,
233
- ...opts?.future,
234
- };
212
+ return { ...opts?.future };
235
213
  },
236
214
  get state() {
237
215
  return {
package/src/lib/errors.ts CHANGED
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/errors.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/errors.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import { isDataWithResponseInit } from './router/router';
4
4
  import { ErrorResponseImpl } from './router/utils';
package/src/lib/hooks.ts CHANGED
@@ -1,4 +1,4 @@
1
- // Transcribed from react-router@7.18.1 lib/hooks.tsx onto octane. Upstream
1
+ // Transcribed from react-router@8.2.0 lib/hooks.tsx onto octane. Upstream
2
2
  // logic, comments, and warning strings are verbatim; octane substitutions:
3
3
  // hooks from 'octane' with the binding slot idiom (splitSlot/subSlot — this
4
4
  // file is NOT compiled, so exported hooks peel the caller's compiler-injected
@@ -23,7 +23,6 @@ import {
23
23
  AwaitContext,
24
24
  DataRouterContext,
25
25
  DataRouterStateContext,
26
- ENABLE_DEV_WARNINGS,
27
26
  LocationContext,
28
27
  NavigationContext,
29
28
  RouteContext,
@@ -55,6 +54,7 @@ import type {
55
54
  import {
56
55
  convertRouteMatchToUiMatch,
57
56
  decodePath,
57
+ ENABLE_DEV_WARNINGS,
58
58
  getResolveToMatches,
59
59
  getRoutePattern,
60
60
  joinPaths,
@@ -223,18 +223,6 @@ export interface NavigateFunction {
223
223
  const navigateEffectWarning =
224
224
  `You should call navigate() in a useEffect(), not when ` + `your component is first rendered.`;
225
225
 
226
- // Mute warnings for calls to useNavigate in SSR environments
227
- function useIsomorphicLayoutEffect(cb: Parameters<typeof useLayoutEffect>[0], slot?: symbol) {
228
- let isStatic = useContext(NavigationContext).static;
229
- if (!isStatic) {
230
- // We should be able to get rid of this once react 18.3 is released
231
- // See: https://github.com/facebook/react/pull/26395
232
- // OCTANE: conditional hook calls are fine — hooks are slot-keyed, not
233
- // call-order keyed.
234
- useLayoutEffect(cb, undefined, subSlot(slot, 'ile'));
235
- }
236
- }
237
-
238
226
  /**
239
227
  * Returns a function that lets you navigate programmatically in the browser in
240
228
  * response to user interactions or effects.
@@ -406,10 +394,11 @@ function useNavigateUnstable(slot?: symbol): NavigateFunction {
406
394
  let routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
407
395
 
408
396
  let activeRef = useRef(false, subSlot(slot, 'unav:ref'));
409
- useIsomorphicLayoutEffect(
397
+ useLayoutEffect(
410
398
  () => {
411
399
  activeRef.current = true;
412
400
  },
401
+ undefined,
413
402
  subSlot(slot, 'unav:ile'),
414
403
  );
415
404
 
@@ -1628,10 +1617,11 @@ function useNavigateStable(slot?: symbol): NavigateFunction {
1628
1617
  let id = useCurrentRouteId(DataRouterStateHook.UseNavigateStable);
1629
1618
 
1630
1619
  let activeRef = useRef(false, subSlot(slot, 'snav:ref'));
1631
- useIsomorphicLayoutEffect(
1620
+ useLayoutEffect(
1632
1621
  () => {
1633
1622
  activeRef.current = true;
1634
1623
  },
1624
+ undefined,
1635
1625
  subSlot(slot, 'snav:ile'),
1636
1626
  );
1637
1627