@solidjs/router 0.10.0-beta.4 → 0.10.0-beta.6

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.
package/README.md CHANGED
@@ -382,12 +382,12 @@ const user = createAsync(() => getUser(params.id))
382
382
 
383
383
  Actions are data mutations that can trigger invalidations and further routing. A list of prebuilt response builders can be found below(TODO).
384
384
  ```jsx
385
+ import { action, revalidate, redirect } from "@solidjs/router"
386
+
385
387
  // anywhere
386
388
  const myAction = action(async (data) => {
387
389
  await doMutation(data);
388
- return redirect("/", {
389
- invalidate: [getUser, data.id]
390
- }) // returns a response
390
+ throw redirect("/", { revalidate: getUser.keyFor(data.id) }); // throw a response to do a redirect
391
391
  });
392
392
 
393
393
  // in component
@@ -456,12 +456,12 @@ function loadUser({params, location}) {
456
456
  <Route path="/users/:id" component={User} load={loadUser} />;
457
457
  ```
458
458
 
459
- The load function is called when the Route is loaded or eagerly when links are hovered. Inside your page component you
459
+ The load function is called when the Route is loaded or eagerly when links are hovered. Inside your page component you:
460
460
 
461
461
  ```jsx
462
462
  // pages/users/[id].js
463
463
  import { getUser } from ... // the cache function
464
-
464
+
465
465
  export default function User(props) {
466
466
  const user = createAsync(() => getUser(props.params.id));
467
467
  return <h1>{user().name}</h1>;
@@ -542,9 +542,9 @@ render(() =>
542
542
  By default, Solid Router uses `location.pathname` as route path. You can simply switch to hash mode through the `source` property on `<Router>` component.
543
543
 
544
544
  ```jsx
545
- import { Router, hashIntegration } from "@solidjs/router";
545
+ import { HashRouter } from "@solidjs/router";
546
546
 
547
- <Router source={hashIntegration()} />;
547
+ <HashRouter />;
548
548
  ```
549
549
 
550
550
  ### Memory Mode Router
@@ -552,11 +552,23 @@ import { Router, hashIntegration } from "@solidjs/router";
552
552
  You can also use memory mode router for testing purpose.
553
553
 
554
554
  ```jsx
555
- import { Router, memoryIntegration } from "@solidjs/router";
555
+ import { MemoryRouter } from "@solidjs/router";
556
+
557
+ <MemoryRouter />;
558
+ ```
559
+
560
+ ### SSR Routing
561
+
562
+ For SSR you can use the static router directly or the browser Router defaults to it on the server, just pass in the url.
563
+
564
+ ```jsx
565
+ import { isServer } from "solid-js/web";
566
+ import { Router } from "@solidjs/router";
556
567
 
557
- <Router source={memoryIntegration()} />;
568
+ <Router url={isServer ? req.url : ""} />;
558
569
  ```
559
570
 
571
+
560
572
  ## Components
561
573
 
562
574
  ### `<A>`
@@ -1,5 +1,5 @@
1
- import type { Component, JSX } from "solid-js";
2
- import type { Location, LocationChangeSignal, MatchFilters, Navigator, RouteLoadFunc, RouterIntegration, RouteSectionProps } from "./types";
1
+ import type { JSX } from "solid-js";
2
+ import type { Location, Navigator } from "./types";
3
3
  declare module "solid-js" {
4
4
  namespace JSX {
5
5
  interface AnchorHTMLAttributes<T> {
@@ -10,27 +10,6 @@ declare module "solid-js" {
10
10
  }
11
11
  }
12
12
  }
13
- export type RouterProps = {
14
- base?: string;
15
- actionBase?: string;
16
- root?: Component<RouteSectionProps>;
17
- children: JSX.Element;
18
- } & ({
19
- url?: never;
20
- source?: RouterIntegration | LocationChangeSignal;
21
- } | {
22
- source?: never;
23
- url: string;
24
- });
25
- export declare const Router: (props: RouterProps) => JSX.Element;
26
- export type RouteProps<S extends string> = {
27
- path?: S | S[];
28
- children?: JSX.Element;
29
- load?: RouteLoadFunc;
30
- matchFilters?: MatchFilters<S>;
31
- component?: Component;
32
- };
33
- export declare const Route: <S extends string>(props: RouteProps<S>) => JSX.Element;
34
13
  export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
35
14
  href: string;
36
15
  replace?: boolean | undefined;
@@ -41,7 +20,6 @@ export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorEle
41
20
  end?: boolean | undefined;
42
21
  }
43
22
  export declare function A(props: AnchorProps): JSX.Element;
44
- export { A as Link, A as NavLink, AnchorProps as LinkProps, AnchorProps as NavLinkProps };
45
23
  export interface NavigateProps {
46
24
  href: ((args: {
47
25
  navigate: Navigator;
@@ -1,85 +1,6 @@
1
- /*@refresh skip*/
2
- import { children, createMemo, createRoot, mergeProps, on, Show, splitProps } from "solid-js";
3
- import { isServer, getRequestEvent } from "solid-js/web";
4
- import { pathIntegration, staticIntegration } from "./integration";
5
- import { createBranches, createRouteContext, createRouterContext, getRouteMatches, RouteContextObj, RouterContextObj, useHref, useLocation, useNavigate, useResolvedPath } from "./routing";
6
- import { normalizePath, createMemoObject } from "./utils";
7
- export const Router = (props) => {
8
- let e;
9
- const { source, url, base, actionBase } = props;
10
- const integration = source ||
11
- (isServer
12
- ? staticIntegration({
13
- value: url || ((e = getRequestEvent()) && getPath(e.request.url)) || ""
14
- })
15
- : pathIntegration());
16
- const routeDefs = children(() => props.children);
17
- const branches = createMemo(() => createBranches(props.root ? { component: props.root, children: routeDefs() } : routeDefs(), props.base || ""));
18
- const routerState = createRouterContext(integration, branches, { base, actionBase });
19
- return (<RouterContextObj.Provider value={routerState}>
20
- <Routes routerState={routerState} branches={branches()}/>
21
- </RouterContextObj.Provider>);
22
- };
23
- function getPath(url) {
24
- const u = new URL(url);
25
- return u.pathname + u.search;
26
- }
27
- function Routes(props) {
28
- const matches = createMemo(() => getRouteMatches(props.branches, props.routerState.location.pathname));
29
- const params = createMemoObject(() => {
30
- const m = matches();
31
- const params = {};
32
- for (let i = 0; i < m.length; i++) {
33
- Object.assign(params, m[i].params);
34
- }
35
- return params;
36
- });
37
- const disposers = [];
38
- let root;
39
- const routeStates = createMemo(on(matches, (nextMatches, prevMatches, prev) => {
40
- let equal = prevMatches && nextMatches.length === prevMatches.length;
41
- const next = [];
42
- for (let i = 0, len = nextMatches.length; i < len; i++) {
43
- const prevMatch = prevMatches && prevMatches[i];
44
- const nextMatch = nextMatches[i];
45
- if (prev && prevMatch && nextMatch.route.key === prevMatch.route.key) {
46
- next[i] = prev[i];
47
- }
48
- else {
49
- equal = false;
50
- if (disposers[i]) {
51
- disposers[i]();
52
- }
53
- createRoot(dispose => {
54
- disposers[i] = dispose;
55
- next[i] = createRouteContext(props.routerState, next[i - 1] || props.routerState.base, createOutlet(() => routeStates()[i + 1]), () => matches()[i], params);
56
- });
57
- }
58
- }
59
- disposers.splice(nextMatches.length).forEach(dispose => dispose());
60
- if (prev && equal) {
61
- return prev;
62
- }
63
- root = next[0];
64
- return next;
65
- }));
66
- return (<Show when={routeStates() && root} keyed>
67
- {route => <RouteContextObj.Provider value={route}>{route.outlet()}</RouteContextObj.Provider>}
68
- </Show>);
69
- }
70
- const createOutlet = (child) => {
71
- return () => (<Show when={child()} keyed>
72
- {child => <RouteContextObj.Provider value={child}>{child.outlet()}</RouteContextObj.Provider>}
73
- </Show>);
74
- };
75
- export const Route = (props) => {
76
- const childRoutes = children(() => props.children);
77
- return mergeProps(props, {
78
- get children() {
79
- return childRoutes();
80
- }
81
- });
82
- };
1
+ import { createMemo, mergeProps, splitProps } from "solid-js";
2
+ import { useHref, useLocation, useNavigate, useResolvedPath } from "./routing";
3
+ import { normalizePath } from "./utils";
83
4
  export function A(props) {
84
5
  props = mergeProps({ inactiveClass: "inactive", activeClass: "active" }, props);
85
6
  const [, rest] = splitProps(props, [
@@ -108,8 +29,6 @@ export function A(props) {
108
29
  ...rest.classList
109
30
  }} aria-current={isActive() ? "page" : undefined}/>);
110
31
  }
111
- // deprecated alias exports
112
- export { A as Link, A as NavLink };
113
32
  export function Navigate(props) {
114
33
  const navigate = useNavigate();
115
34
  const location = useLocation();
@@ -1,6 +1,7 @@
1
1
  import { JSX } from "solid-js";
2
2
  import { Submission } from "../types";
3
3
  export type Action<T, U> = ((vars: T) => Promise<U>) & JSX.SerializableAttributeValue;
4
+ export declare const actions: Map<string, Function>;
4
5
  export declare function useSubmissions<T, U>(fn: Action<T, U>, filter?: (arg: T) => boolean): Submission<T, U>[] & {
5
6
  pending: boolean;
6
7
  };
@@ -1,8 +1,9 @@
1
1
  import { $TRACK, createMemo, createSignal } from "solid-js";
2
2
  import { isServer } from "solid-js/web";
3
- import { registerAction, useRouter } from "../routing";
3
+ import { useRouter } from "../routing";
4
4
  import { redirectStatusCodes } from "../utils";
5
5
  import { revalidate } from "./cache";
6
+ export const actions = /* #__PURE__ */ new Map();
6
7
  export function useSubmissions(fn, filter) {
7
8
  const router = useRouter();
8
9
  const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.toString() && (!filter || filter(s.input))));
@@ -18,26 +19,11 @@ export function useSubmissions(fn, filter) {
18
19
  }
19
20
  export function useSubmission(fn, filter) {
20
21
  const submissions = useSubmissions(fn, filter);
21
- return {
22
- get clear() {
23
- return submissions[submissions.length - 1]?.clear;
24
- },
25
- get retry() {
26
- return submissions[submissions.length - 1]?.retry;
27
- },
28
- get url() {
29
- return submissions[submissions.length - 1]?.url;
30
- },
31
- get input() {
32
- return submissions[submissions.length - 1]?.input;
33
- },
34
- get result() {
35
- return submissions[submissions.length - 1]?.result;
36
- },
37
- get pending() {
38
- return submissions[submissions.length - 1]?.pending;
22
+ return new Proxy({}, {
23
+ get(_, property) {
24
+ return submissions[submissions.length - 1]?.[property];
39
25
  }
40
- };
26
+ });
41
27
  }
42
28
  export function useAction(action) {
43
29
  const router = useRouter();
@@ -86,23 +72,30 @@ export function action(fn, name) {
86
72
  return url;
87
73
  };
88
74
  if (!isServer)
89
- registerAction(url, mutate);
75
+ actions.set(url, mutate);
90
76
  return mutate;
91
77
  }
92
78
  async function handleResponse(response, navigate) {
93
79
  let data;
94
- if (response instanceof Response && redirectStatusCodes.has(response.status)) {
95
- const locationUrl = response.headers.get("Location") || "/";
96
- if (locationUrl.startsWith("http")) {
97
- window.location.href = locationUrl;
80
+ let keys;
81
+ if (response instanceof Response) {
82
+ if (response.headers.has("X-Revalidate")) {
83
+ keys = response.headers.get("X-Revalidate").split(",");
98
84
  }
99
- else {
100
- navigate(locationUrl);
85
+ if (response.customBody)
86
+ data = await response.customBody();
87
+ if (redirectStatusCodes.has(response.status)) {
88
+ const locationUrl = response.headers.get("Location") || "/";
89
+ if (locationUrl.startsWith("http")) {
90
+ window.location.href = locationUrl;
91
+ }
92
+ else {
93
+ navigate(locationUrl);
94
+ }
101
95
  }
102
96
  }
103
97
  else
104
98
  data = response;
105
- // TODO: handle keys
106
- await revalidate();
99
+ await revalidate(keys);
107
100
  return data;
108
101
  }
@@ -1,3 +1,7 @@
1
1
  import { type ReconcileOptions } from "solid-js/store";
2
- export declare function revalidate(key?: string | any[] | void): Promise<void>;
3
- export declare function cache<T extends (...args: any) => U | Response, U>(fn: T, name: string, options?: ReconcileOptions): T;
2
+ export declare function revalidate(key?: string | string[] | void): Promise<void>;
3
+ export type CachedFunction<T extends (...args: any) => U | Response, U> = T & {
4
+ keyFor: (...args: Parameters<T>) => string;
5
+ key: string;
6
+ };
7
+ export declare function cache<T extends (...args: any) => U | Response, U>(fn: T, name: string, options?: ReconcileOptions): CachedFunction<T, U>;
@@ -5,7 +5,19 @@ import { useNavigate, getIntent } from "../routing";
5
5
  import { redirectStatusCodes } from "../utils";
6
6
  const LocationHeader = "Location";
7
7
  const PRELOAD_TIMEOUT = 5000;
8
+ const CACHE_TIMEOUT = 180000;
8
9
  let cacheMap = new Map();
10
+ // cleanup forward/back cache
11
+ if (!isServer) {
12
+ setInterval(() => {
13
+ const now = Date.now();
14
+ for (let [k, v] of cacheMap.entries()) {
15
+ if (!v[3].size && now - v[0] > CACHE_TIMEOUT) {
16
+ cacheMap.delete(k);
17
+ }
18
+ }
19
+ }, 300000);
20
+ }
9
21
  function getCache() {
10
22
  if (!isServer)
11
23
  return cacheMap;
@@ -13,13 +25,14 @@ function getCache() {
13
25
  return req.routerCache || (req.routerCache = new Map());
14
26
  }
15
27
  export function revalidate(key) {
28
+ key && !Array.isArray(key) && (key = [key]);
16
29
  return startTransition(() => {
17
30
  const now = Date.now();
18
31
  for (let k of cacheMap.keys()) {
19
- if (key === undefined || k === key) {
20
- const set = cacheMap.get(k)[3];
21
- revalidateSignals(set, now);
22
- cacheMap.delete(k);
32
+ if (key === undefined || matchKey(k, key)) {
33
+ const entry = cacheMap.get(k);
34
+ entry[0] = 0; //force cache miss
35
+ revalidateSignals(entry[3], now); // retrigger live signals
23
36
  }
24
37
  }
25
38
  });
@@ -30,13 +43,13 @@ function revalidateSignals(set, time) {
30
43
  }
31
44
  export function cache(fn, name, options) {
32
45
  const [store, setStore] = createStore({});
33
- return ((...args) => {
46
+ const cachedFn = ((...args) => {
34
47
  const cache = getCache();
35
48
  const intent = getIntent();
36
49
  const owner = getOwner();
37
50
  const navigate = owner ? useNavigate() : undefined;
38
51
  const now = Date.now();
39
- const key = name + (args.length ? ":" + args.join(":") : "");
52
+ const key = name + hashKey(args);
40
53
  let cached = cache.get(key);
41
54
  let version;
42
55
  if (owner) {
@@ -53,9 +66,10 @@ export function cache(fn, name, options) {
53
66
  }
54
67
  let res = cached[1];
55
68
  if (!isServer && intent === "navigate") {
56
- res = "then" in cached[1]
57
- ? cached[1].then(handleResponse(false), handleResponse(true))
58
- : handleResponse(false)(cached[1]);
69
+ res =
70
+ "then" in cached[1]
71
+ ? cached[1].then(handleResponse(false), handleResponse(true))
72
+ : handleResponse(false)(cached[1]);
59
73
  startTransition(() => revalidateSignals(cached[3], cached[0])); // update version
60
74
  }
61
75
  return res;
@@ -79,9 +93,10 @@ export function cache(fn, name, options) {
79
93
  else
80
94
  cache.set(key, (cached = [now, res, intent, new Set(version ? [version] : [])]));
81
95
  if (intent !== "preload") {
82
- res = "then" in res
83
- ? res.then(handleResponse(false), handleResponse(true))
84
- : handleResponse(false)(res);
96
+ res =
97
+ "then" in res
98
+ ? res.then(handleResponse(false), handleResponse(true))
99
+ : handleResponse(false)(res);
85
100
  }
86
101
  return res;
87
102
  function handleResponse(error) {
@@ -111,4 +126,32 @@ export function cache(fn, name, options) {
111
126
  };
112
127
  }
113
128
  });
129
+ cachedFn.keyFor = (...args) => name + hashKey(args);
130
+ cachedFn.key = name;
131
+ return cachedFn;
132
+ }
133
+ function matchKey(key, keys) {
134
+ for (let k of keys) {
135
+ if (key.startsWith(k))
136
+ return true;
137
+ }
138
+ return false;
139
+ }
140
+ // Modified from the amazing Tanstack Query library (MIT)
141
+ // https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L168
142
+ function hashKey(args) {
143
+ return JSON.stringify(args, (_, val) => isPlainObject(val)
144
+ ? Object.keys(val)
145
+ .sort()
146
+ .reduce((result, key) => {
147
+ result[key] = val[key];
148
+ return result;
149
+ }, {})
150
+ : val);
151
+ }
152
+ function isPlainObject(obj) {
153
+ let proto;
154
+ return (obj != null &&
155
+ typeof obj === "object" &&
156
+ (!(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype));
114
157
  }
@@ -0,0 +1,2 @@
1
+ import type { RouterContext } from "../types";
2
+ export declare function setupNativeEvents(router: RouterContext): void;
@@ -0,0 +1,116 @@
1
+ import { delegateEvents } from "solid-js/web";
2
+ import { onCleanup } from "solid-js";
3
+ import { actions } from "./action";
4
+ export function setupNativeEvents(router) {
5
+ const basePath = router.base.path();
6
+ const navigateFromRoute = router.navigatorFactory(router.base);
7
+ let preloadTimeout = {};
8
+ function isSvg(el) {
9
+ return el.namespaceURI === "http://www.w3.org/2000/svg";
10
+ }
11
+ function handleAnchor(evt) {
12
+ if (evt.defaultPrevented ||
13
+ evt.button !== 0 ||
14
+ evt.metaKey ||
15
+ evt.altKey ||
16
+ evt.ctrlKey ||
17
+ evt.shiftKey)
18
+ return;
19
+ const a = evt
20
+ .composedPath()
21
+ .find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
22
+ if (!a)
23
+ return;
24
+ const svg = isSvg(a);
25
+ const href = svg ? a.href.baseVal : a.href;
26
+ const target = svg ? a.target.baseVal : a.target;
27
+ if (target || (!href && !a.hasAttribute("state")))
28
+ return;
29
+ const rel = (a.getAttribute("rel") || "").split(/\s+/);
30
+ if (a.hasAttribute("download") || (rel && rel.includes("external")))
31
+ return;
32
+ const url = svg ? new URL(href, document.baseURI) : new URL(href);
33
+ if (url.origin !== window.location.origin ||
34
+ (basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())))
35
+ return;
36
+ return [a, url];
37
+ }
38
+ function handleAnchorClick(evt) {
39
+ const res = handleAnchor(evt);
40
+ if (!res)
41
+ return;
42
+ const [a, url] = res;
43
+ const to = router.parsePath(url.pathname + url.search + url.hash);
44
+ const state = a.getAttribute("state");
45
+ evt.preventDefault();
46
+ navigateFromRoute(to, {
47
+ resolve: false,
48
+ replace: a.hasAttribute("replace"),
49
+ scroll: !a.hasAttribute("noscroll"),
50
+ state: state && JSON.parse(state)
51
+ });
52
+ }
53
+ function handleAnchorPreload(evt) {
54
+ const res = handleAnchor(evt);
55
+ if (!res)
56
+ return;
57
+ const [a, url] = res;
58
+ if (!preloadTimeout[url.pathname])
59
+ router.preloadRoute(url, a.getAttribute("preload") !== "false");
60
+ }
61
+ function handleAnchorIn(evt) {
62
+ const res = handleAnchor(evt);
63
+ if (!res)
64
+ return;
65
+ const [a, url] = res;
66
+ if (preloadTimeout[url.pathname])
67
+ return;
68
+ preloadTimeout[url.pathname] = setTimeout(() => {
69
+ router.preloadRoute(url, a.getAttribute("preload") !== "false");
70
+ delete preloadTimeout[url.pathname];
71
+ }, 200);
72
+ }
73
+ function handleAnchorOut(evt) {
74
+ const res = handleAnchor(evt);
75
+ if (!res)
76
+ return;
77
+ const [, url] = res;
78
+ if (preloadTimeout[url.pathname]) {
79
+ clearTimeout(preloadTimeout[url.pathname]);
80
+ delete preloadTimeout[url.pathname];
81
+ }
82
+ }
83
+ function handleFormSubmit(evt) {
84
+ let actionRef = (evt.submitter && evt.submitter.getAttribute("formaction")) || evt.target.action;
85
+ if (!actionRef)
86
+ return;
87
+ if (!actionRef.startsWith("action:")) {
88
+ const url = new URL(actionRef);
89
+ actionRef = router.parsePath(url.pathname + url.search);
90
+ if (!actionRef.startsWith(router.actionBase))
91
+ return;
92
+ }
93
+ const handler = actions.get(actionRef);
94
+ if (handler) {
95
+ evt.preventDefault();
96
+ const data = new FormData(evt.target);
97
+ handler.call(router, data);
98
+ }
99
+ }
100
+ // ensure delegated event run first
101
+ delegateEvents(["click", "submit"]);
102
+ document.addEventListener("click", handleAnchorClick);
103
+ document.addEventListener("mouseover", handleAnchorIn);
104
+ document.addEventListener("mouseout", handleAnchorOut);
105
+ document.addEventListener("focusin", handleAnchorPreload);
106
+ document.addEventListener("touchstart", handleAnchorPreload);
107
+ document.addEventListener("submit", handleFormSubmit);
108
+ onCleanup(() => {
109
+ document.removeEventListener("click", handleAnchorClick);
110
+ document.removeEventListener("mouseover", handleAnchorIn);
111
+ document.removeEventListener("mouseout", handleAnchorOut);
112
+ document.removeEventListener("focusin", handleAnchorPreload);
113
+ document.removeEventListener("touchstart", handleAnchorPreload);
114
+ document.removeEventListener("submit", handleFormSubmit);
115
+ });
116
+ }
@@ -1,4 +1,4 @@
1
1
  export { createAsync } from "./createAsync";
2
- export { action, useSubmission, useSubmissions, useAction } from "./action";
3
- export { cache, revalidate } from "./cache";
2
+ export { action, useSubmission, useSubmissions, useAction, type Action } from "./action";
3
+ export { cache, revalidate, type CachedFunction } from "./cache";
4
4
  export { redirect } from "./response";
@@ -1 +1,5 @@
1
- export declare function redirect(url: string, init?: number | ResponseInit): Response;
1
+ export type RouterResponseInit = ResponseInit & {
2
+ revalidate?: string | string[];
3
+ };
4
+ export declare function redirect(url: string, init?: number | RouterResponseInit): Response;
5
+ export declare function reload(init: RouterResponseInit): Response;
@@ -1,16 +1,28 @@
1
1
  export function redirect(url, init = 302) {
2
- let responseInit = init;
3
- if (typeof responseInit === "number") {
4
- responseInit = { status: responseInit };
2
+ let responseInit;
3
+ let revalidate;
4
+ if (typeof init === "number") {
5
+ responseInit = { status: init };
5
6
  }
6
- else if (typeof responseInit.status === "undefined") {
7
- responseInit.status = 302;
7
+ else {
8
+ ({ revalidate, ...responseInit } = init);
9
+ if (typeof responseInit.status === "undefined") {
10
+ responseInit.status = 302;
11
+ }
8
12
  }
9
13
  const headers = new Headers(responseInit.headers);
10
14
  headers.set("Location", url);
15
+ revalidate && headers.set("X-Revalidate", revalidate.toString());
11
16
  const response = new Response(null, {
12
17
  ...responseInit,
13
18
  headers: headers
14
19
  });
15
20
  return response;
16
21
  }
22
+ export function reload(init) {
23
+ const { revalidate, ...responseInit } = init;
24
+ return new Response(null, {
25
+ ...responseInit,
26
+ ...(revalidate ? { headers: new Headers(responseInit.headers).set("X-Revalidate", revalidate.toString()) } : {})
27
+ });
28
+ }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
+ export * from "./routers";
1
2
  export * from "./components";
2
- export * from "./integration";
3
3
  export * from "./lifecycle";
4
4
  export { useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, } from "./routing";
5
5
  export { mergeSearchString as _mergeSearchString } from "./utils";
6
6
  export * from "./data";
7
- export type { Location, LocationChange, LocationChangeSignal, NavigateOptions, Navigator, OutputMatch, Params, RouteSectionProps, RouteLoadFunc, RouteLoadFuncArgs, RouteDefinition, RouterIntegration, RouterOutput, RouterUtils, SetParams, BeforeLeaveEventArgs } from "./types";
7
+ export type { Location, LocationChange, NavigateOptions, Navigator, OutputMatch, Params, RouteSectionProps, RouteLoadFunc, RouteLoadFuncArgs, RouteDefinition, RouterIntegration, RouterOutput, RouterUtils, SetParams, BeforeLeaveEventArgs } from "./types";