@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
@@ -1,7 +1,7 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/router/utils.ts — unmodified except: type-only react import → local ../react-types shim.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/router/utils.ts — unmodified except: React types → local ../react-types shim; route descriptors → octane createElement; build-time __DEV__ constant → NODE_ENV check.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import type * as React from '../react-types';
4
- import type { MiddlewareEnabled } from '../types/future';
4
+ import { createElement } from 'octane';
5
5
  import type { Equal, Expect } from '../types/utils';
6
6
  import type { Location, Path, To } from './history';
7
7
  import { invariant, parsePath, warning } from './history';
@@ -11,6 +11,8 @@ import {
11
11
  PROTOCOL_RELATIVE_URL_REGEX,
12
12
  } from './url';
13
13
 
14
+ export const ENABLE_DEV_WARNINGS = process.env.NODE_ENV !== 'production';
15
+
14
16
  export type MaybePromise<T> = T | Promise<T>;
15
17
 
16
18
  /**
@@ -265,7 +267,7 @@ export class RouterContextProvider {
265
267
  }
266
268
  }
267
269
 
268
- type DefaultContext = MiddlewareEnabled extends true ? Readonly<RouterContextProvider> : any;
270
+ type DefaultContext = Readonly<RouterContextProvider>;
269
271
 
270
272
  /**
271
273
  * @private
@@ -277,11 +279,11 @@ interface DataFunctionArgs<Context> {
277
279
  request: Request;
278
280
  /**
279
281
  * A URL instance representing the application location being navigated to or
280
- * fetched. By default, this matches `request.url`.
282
+ * fetched.
281
283
  *
282
- * In Framework mode with `future.v8_passThroughRequests` enabled, this is a
283
- * normalized URL with React-Router-specific implementation details removed
284
- * (`.data` suffixes, `index`/`_routes` search params).
284
+ * In Framework mode, this is a normalized URL with React-Router-specific
285
+ * implementation details removed (`.data` suffixes, `index`/`_routes` search
286
+ * params). For the raw incoming URL, use `request.url`.
285
287
  */
286
288
  url: URL;
287
289
  /**
@@ -548,9 +550,7 @@ export type PatchRoutesOnNavigationFunction = (
548
550
  * Function provided to set route-specific properties from route objects
549
551
  */
550
552
  export interface MapRoutePropertiesFunction {
551
- (route: DataRouteObject): {
552
- hasErrorBoundary: boolean;
553
- } & Record<string, any>;
553
+ (route: DataRouteObject): Partial<DataRouteObject>;
554
554
  }
555
555
 
556
556
  /**
@@ -654,8 +654,6 @@ export type BaseRouteObject = {
654
654
  * See [`action`](../../start/data/route-object#action).
655
655
  */
656
656
  action?: ActionFunction | boolean;
657
- // TODO(v8): deprecate/remove
658
- hasErrorBoundary?: boolean;
659
657
  /**
660
658
  * The route shouldRevalidate function.
661
659
  * See [`shouldRevalidate`](../../start/data/route-object#shouldRevalidate).
@@ -880,11 +878,65 @@ function isIndexRoute(route: RouteObject): route is IndexRouteObject {
880
878
  return route.index === true;
881
879
  }
882
880
 
881
+ export function defaultMapRouteProperties(route: DataRouteObject) {
882
+ let updates: Partial<DataRouteObject> = {};
883
+
884
+ if (route.Component) {
885
+ if (ENABLE_DEV_WARNINGS) {
886
+ if (route.element) {
887
+ warning(
888
+ false,
889
+ 'You should not include both `Component` and `element` on your route - ' +
890
+ '`Component` will be used.',
891
+ );
892
+ }
893
+ }
894
+ Object.assign(updates, {
895
+ element: createElement(route.Component),
896
+ Component: undefined,
897
+ });
898
+ }
899
+
900
+ if (route.HydrateFallback) {
901
+ if (ENABLE_DEV_WARNINGS) {
902
+ if (route.hydrateFallbackElement) {
903
+ warning(
904
+ false,
905
+ 'You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - ' +
906
+ '`HydrateFallback` will be used.',
907
+ );
908
+ }
909
+ }
910
+ Object.assign(updates, {
911
+ hydrateFallbackElement: createElement(route.HydrateFallback),
912
+ HydrateFallback: undefined,
913
+ });
914
+ }
915
+
916
+ if (route.ErrorBoundary) {
917
+ if (ENABLE_DEV_WARNINGS) {
918
+ if (route.errorElement) {
919
+ warning(
920
+ false,
921
+ 'You should not include both `ErrorBoundary` and `errorElement` on your route - ' +
922
+ '`ErrorBoundary` will be used.',
923
+ );
924
+ }
925
+ }
926
+ Object.assign(updates, {
927
+ errorElement: createElement(route.ErrorBoundary),
928
+ ErrorBoundary: undefined,
929
+ });
930
+ }
931
+
932
+ return updates;
933
+ }
934
+
883
935
  // Walk the route tree generating unique IDs where necessary, so we are working
884
936
  // solely with DataRouteObject's within the Router
885
937
  export function convertRoutesToDataRoutes(
886
938
  routes: RouteObject[],
887
- mapRouteProperties: MapRoutePropertiesFunction,
939
+ mapRouteProperties: MapRoutePropertiesFunction = defaultMapRouteProperties,
888
940
  parentPath: string[] = [],
889
941
  manifest: RouteManifest = {},
890
942
  allowInPlaceMutations = false,
@@ -931,7 +983,7 @@ export function convertRoutesToDataRoutes(
931
983
 
932
984
  function mergeRouteUpdates<T extends DataRouteObject>(
933
985
  route: T,
934
- updates: ReturnType<MapRoutePropertiesFunction>,
986
+ updates: Partial<DataRouteObject>,
935
987
  ): T {
936
988
  return Object.assign(route, {
937
989
  ...updates,
@@ -1019,14 +1071,6 @@ export interface UIMatch<Data = unknown, Handle = unknown> {
1019
1071
  * {@link https://reactrouter.com/start/framework/routing#dynamic-segments Dynamic route params} for the matched route.
1020
1072
  */
1021
1073
  params: RouteMatch['params'];
1022
- /**
1023
- * The return value from the matched route's loader or clientLoader. This might
1024
- * be `undefined` if this route's `loader` (or a deeper route's `loader`) threw
1025
- * an error and we're currently displaying an `ErrorBoundary`.
1026
- *
1027
- * @deprecated Use `UIMatch.loaderData` instead
1028
- */
1029
- data: Data | undefined;
1030
1074
  /**
1031
1075
  * The return value from the matched route's loader or clientLoader. This might
1032
1076
  * be `undefined` if this route's `loader` (or a deeper route's `loader`) threw
@@ -1046,7 +1090,6 @@ export function convertRouteMatchToUiMatch(match: DataRouteMatch, loaderData: Ro
1046
1090
  id: route.id,
1047
1091
  pathname,
1048
1092
  params,
1049
- data: loaderData[route.id],
1050
1093
  loaderData: loaderData[route.id],
1051
1094
  handle: route.handle,
1052
1095
  };
@@ -1243,6 +1286,8 @@ function rankRouteBranches(branches: RouteBranch[]): void {
1243
1286
  }
1244
1287
 
1245
1288
  const paramRe = /^:[\w-]+$/;
1289
+ const partialParamRe = /^:[\w-]+/;
1290
+ const partialDynamicSegmentValue = 3.5;
1246
1291
  const dynamicSegmentValue = 3;
1247
1292
  const indexRouteValue = 2;
1248
1293
  const emptySegmentValue = 1;
@@ -1265,12 +1310,13 @@ function computeScore(path: string, index: boolean | undefined): number {
1265
1310
  .filter((s) => !isSplat(s))
1266
1311
  .reduce(
1267
1312
  (score, segment) =>
1268
- score +
1269
- (paramRe.test(segment)
1270
- ? dynamicSegmentValue
1271
- : segment === ''
1272
- ? emptySegmentValue
1273
- : staticSegmentValue),
1313
+ // prettier-ignore
1314
+ score + (
1315
+ paramRe.test(segment) ? dynamicSegmentValue :
1316
+ partialParamRe.test(segment) ? partialDynamicSegmentValue :
1317
+ segment === "" ? emptySegmentValue :
1318
+ staticSegmentValue
1319
+ ),
1274
1320
  initialScore,
1275
1321
  );
1276
1322
  }
@@ -1577,7 +1623,7 @@ export function compilePath(
1577
1623
  return '/([^\\/]+)';
1578
1624
  },
1579
1625
  ) // Dynamic segment
1580
- .replace(/\/([\w-]+)\?(\/|$)/g, '(/$1)?$2'); // Optional static segment
1626
+ .replace(/\/([\w-]+)\?(?=\/|$|\()/g, '(?:/$1)?'); // Optional static segment (non-capturing)
1581
1627
 
1582
1628
  if (path.endsWith('*')) {
1583
1629
  params.push({ paramName: '*' });
@@ -2108,11 +2154,41 @@ by the star-slash in the `getRoutePattern` regex and messes up the parsed commen
2108
2154
  for `isRouteErrorResponse` above. This comment seems to reset the parser.
2109
2155
  */
2110
2156
 
2111
- export function getRoutePattern(matches: RouteMatch[]) {
2157
+ // Accept the narrow shape we read so this can be used with server-runtime
2158
+ // matches, which do not include the full RouteMatch fields like pathnameBase.
2159
+ export function getRoutePattern(matches: { route: { path?: string } }[]) {
2112
2160
  let parts = matches.map((m) => m.route.path).filter(Boolean) as string[];
2113
2161
  return joinPaths(parts) || '/';
2114
2162
  }
2115
2163
 
2164
+ // Create the normalized URL instance to pass to loaders/actions/middleware.
2165
+ // We strip the `?index` param because that is a React Router implementation detail.
2166
+ export function createDataFunctionUrl(request: Request | URL | string, path: To): URL {
2167
+ let url = new URL(typeof request === 'string' || request instanceof URL ? request : request.url);
2168
+
2169
+ let parsed = typeof path === 'string' ? parsePath(path) : path;
2170
+ url.pathname = parsed.pathname || '/';
2171
+
2172
+ if (parsed.search) {
2173
+ let searchParams = new URLSearchParams(parsed.search);
2174
+
2175
+ // Strip naked index param, preserve any other index params with values
2176
+ let indexValues = searchParams.getAll('index');
2177
+ searchParams.delete('index');
2178
+ for (let value of indexValues.filter(Boolean)) {
2179
+ searchParams.append('index', value);
2180
+ }
2181
+ let search = searchParams.toString();
2182
+ url.search = search ? `?${search}` : '';
2183
+ } else {
2184
+ url.search = '';
2185
+ }
2186
+
2187
+ url.hash = parsed.hash || '';
2188
+
2189
+ return url;
2190
+ }
2191
+
2116
2192
  export const isBrowser =
2117
2193
  typeof window !== 'undefined' &&
2118
2194
  typeof window.document !== 'undefined' &&
@@ -1,12 +1,12 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/cookies.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/server-runtime/cookies.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
- import type { ParseOptions, SerializeOptions } from 'cookie';
4
- import { parse, serialize } from 'cookie';
3
+ import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es';
4
+ import { parse, serialize } from 'cookie-es';
5
5
 
6
6
  import { sign, unsign } from './crypto';
7
7
  import { warnOnce } from './warnings';
8
8
 
9
- export type { ParseOptions as CookieParseOptions, SerializeOptions as CookieSerializeOptions };
9
+ export type { CookieParseOptions, CookieSerializeOptions };
10
10
 
11
11
  export interface CookieSignatureOptions {
12
12
  /**
@@ -20,7 +20,7 @@ export interface CookieSignatureOptions {
20
20
  secrets?: string[];
21
21
  }
22
22
 
23
- export type CookieOptions = ParseOptions & SerializeOptions & CookieSignatureOptions;
23
+ export type CookieOptions = CookieParseOptions & CookieSerializeOptions & CookieSignatureOptions;
24
24
 
25
25
  /**
26
26
  * A HTTP cookie.
@@ -55,13 +55,13 @@ export interface Cookie {
55
55
  * Parses a raw `Cookie` header and returns the value of this cookie or
56
56
  * `null` if it's not present.
57
57
  */
58
- parse(cookieHeader: string | null, options?: ParseOptions): Promise<any>;
58
+ parse(cookieHeader: string | null, options?: CookieParseOptions): Promise<any>;
59
59
 
60
60
  /**
61
61
  * Serializes the given value to a string and returns the `Set-Cookie`
62
62
  * header.
63
63
  */
64
- serialize(value: any, options?: SerializeOptions): Promise<string>;
64
+ serialize(value: any, options?: CookieSerializeOptions): Promise<string>;
65
65
  }
66
66
 
67
67
  /**
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/crypto.ts — unmodified except: type-only: bare Uint8Array return widens to Uint8Array<ArrayBufferLike> under TS 5.7+ typed-array generics, which crypto.subtle.verify's BufferSource rejects.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/server-runtime/crypto.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  const encoder = /* @__PURE__ */ new TextEncoder();
4
4
 
@@ -45,7 +45,7 @@ const createKey = async (secret: string, usages: CryptoKey['usages']): Promise<C
45
45
  );
46
46
 
47
47
  function byteStringToUint8Array(byteString: string): Uint8Array<ArrayBuffer> {
48
- let array = new Uint8Array(byteString.length);
48
+ let array: Uint8Array<ArrayBuffer> = new Uint8Array(byteString.length);
49
49
 
50
50
  for (let i = 0; i < byteString.length; i++) {
51
51
  array[i] = byteString.charCodeAt(i);
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/mode.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/server-runtime/mode.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  /**
4
4
  * The mode to use when running the server.
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/sessions/cookieStorage.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/server-runtime/sessions/cookieStorage.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import { createCookie, isCookie } from '../cookies';
4
4
  import type { SessionStorage, SessionIdStorageStrategy, SessionData } from '../sessions';
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/sessions/memoryStorage.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/server-runtime/sessions/memoryStorage.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import type {
4
4
  SessionData,
@@ -1,6 +1,6 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/sessions.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/server-runtime/sessions.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
- import type { ParseOptions, SerializeOptions } from 'cookie';
3
+ import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es';
4
4
 
5
5
  import type { Cookie, CookieOptions } from './cookies';
6
6
  import { createCookie, isCookie } from './cookies';
@@ -167,14 +167,17 @@ export interface SessionStorage<Data = SessionData, FlashData = Data> {
167
167
  */
168
168
  getSession: (
169
169
  cookieHeader?: string | null,
170
- options?: ParseOptions,
170
+ options?: CookieParseOptions,
171
171
  ) => Promise<Session<Data, FlashData>>;
172
172
 
173
173
  /**
174
174
  * Stores all data in the Session and returns the Set-Cookie header to be
175
175
  * used in the HTTP response.
176
176
  */
177
- commitSession: (session: Session<Data, FlashData>, options?: SerializeOptions) => Promise<string>;
177
+ commitSession: (
178
+ session: Session<Data, FlashData>,
179
+ options?: CookieSerializeOptions,
180
+ ) => Promise<string>;
178
181
 
179
182
  /**
180
183
  * Deletes all data associated with the Session and returns the Set-Cookie
@@ -182,7 +185,7 @@ export interface SessionStorage<Data = SessionData, FlashData = Data> {
182
185
  */
183
186
  destroySession: (
184
187
  session: Session<Data, FlashData>,
185
- options?: SerializeOptions,
188
+ options?: CookieSerializeOptions,
186
189
  ) => Promise<string>;
187
190
  }
188
191
 
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/server-runtime/warnings.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/server-runtime/warnings.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  const alreadyWarned: { [message: string]: boolean } = {};
4
4
 
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/types/future.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/types/future.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  /**
4
4
  * An augmentable interface users can modify in their app-code to opt into
@@ -7,10 +7,4 @@
7
7
  export interface Future {
8
8
  // We list the potential fields here in comments strictly for clarity.
9
9
  // They will be generated by the react-router/dev/typegen/generate.ts module
10
- //
11
- // v8_middleware: boolean
12
10
  }
13
-
14
- // prettier-ignore
15
- export type MiddlewareEnabled =
16
- Future extends { v8_middleware: infer T extends boolean; } ? T : false
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/types/params.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/types/params.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import type { Pages, RouteFiles } from './register';
4
4
  import type { Normalize } from './utils';
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/types/register.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/types/register.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import type { RouteModule } from './route-module';
4
4
 
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/types/route-module.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/types/route-module.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  import type { Func } from './utils';
4
4
 
@@ -1,4 +1,4 @@
1
- // Vendored from react-router@7.18.1 packages/react-router/lib/types/utils.ts — unmodified.
1
+ // Vendored from react-router@8.2.0 packages/react-router/lib/types/utils.ts — unmodified.
2
2
  // Re-vendor with `node scripts/vendor-remix-router.mjs`; never hand-edit.
3
3
  export type Expect<T extends true> = T;
4
4