Files
FrenoCorp/node_modules/@solidjs/router/dist/index.js
Michael Freno 7c684a42cc FRE-600: Fix code review blockers
- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 00:08:01 -04:00

1880 lines
56 KiB
JavaScript

import { isServer, getRequestEvent, createComponent as createComponent$1, memo, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';
import { getOwner, runWithOwner, createMemo, createContext, onCleanup, useContext, untrack, createSignal, createRenderEffect, on, startTransition, resetErrorBoundaries, batch, createComponent, children, mergeProps, Show, createRoot, sharedConfig, getListener, $TRACK, splitProps, createResource, catchError } from 'solid-js';
import { createStore, reconcile, unwrap } from 'solid-js/store';
function createBeforeLeave() {
let listeners = new Set();
function subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
}
let ignore = false;
function confirm(to, options) {
if (ignore) return !(ignore = false);
const e = {
to,
options,
defaultPrevented: false,
preventDefault: () => e.defaultPrevented = true
};
for (const l of listeners) l.listener({
...e,
from: l.location,
retry: force => {
force && (ignore = true);
l.navigate(to, {
...options,
resolve: false
});
}
});
return !e.defaultPrevented;
}
return {
subscribe,
confirm
};
}
// The following supports browser initiated blocking (eg back/forward)
let depth;
function saveCurrentDepth() {
if (!window.history.state || window.history.state._depth == null) {
window.history.replaceState({
...window.history.state,
_depth: window.history.length - 1
}, "");
}
depth = window.history.state._depth;
}
if (!isServer) {
saveCurrentDepth();
}
function keepDepth(state) {
return {
...state,
_depth: window.history.state && window.history.state._depth
};
}
function notifyIfNotBlocked(notify, block) {
let ignore = false;
return () => {
const prevDepth = depth;
saveCurrentDepth();
const delta = prevDepth == null ? null : depth - prevDepth;
if (ignore) {
ignore = false;
return;
}
if (delta && block(delta)) {
ignore = true;
window.history.go(-delta);
} else {
notify();
}
};
}
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
const trimPathRegex = /^\/+|(\/)\/+$/g;
const mockBase = "http://sr";
function normalizePath(path, omitSlash = false) {
const s = path.replace(trimPathRegex, "$1");
return s ? omitSlash || /^[?#]/.test(s) ? s : "/" + s : "";
}
function resolvePath(base, path, from) {
if (hasSchemeRegex.test(path)) {
return undefined;
}
const basePath = normalizePath(base);
const fromPath = from && normalizePath(from);
let result = "";
if (!fromPath || path.startsWith("/")) {
result = basePath;
} else if (fromPath.toLowerCase().indexOf(basePath.toLowerCase()) !== 0) {
result = basePath + fromPath;
} else {
result = fromPath;
}
return (result || "/") + normalizePath(path, !result);
}
function invariant(value, message) {
if (value == null) {
throw new Error(message);
}
return value;
}
function joinPaths(from, to) {
return normalizePath(from).replace(/\/*(\*.*)?$/g, "") + normalizePath(to);
}
function extractSearchParams(url) {
const params = {};
url.searchParams.forEach((value, key) => {
if (key in params) {
if (Array.isArray(params[key])) params[key].push(value);else params[key] = [params[key], value];
} else params[key] = value;
});
return params;
}
function createMatcher(path, partial, matchFilters) {
const [pattern, splat] = path.split("/*", 2);
const segments = pattern.split("/").filter(Boolean);
const len = segments.length;
return location => {
const locSegments = location.split("/").filter(Boolean);
const lenDiff = locSegments.length - len;
if (lenDiff < 0 || lenDiff > 0 && splat === undefined && !partial) {
return null;
}
const match = {
path: len ? "" : "/",
params: {}
};
const matchFilter = s => matchFilters === undefined ? undefined : matchFilters[s];
for (let i = 0; i < len; i++) {
const segment = segments[i];
const dynamic = segment[0] === ":";
const locSegment = dynamic ? locSegments[i] : locSegments[i].toLowerCase();
const key = dynamic ? segment.slice(1) : segment.toLowerCase();
if (dynamic && matchSegment(locSegment, matchFilter(key))) {
match.params[key] = locSegment;
} else if (dynamic || !matchSegment(locSegment, key)) {
return null;
}
match.path += `/${locSegment}`;
}
if (splat) {
const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
if (matchSegment(remainder, matchFilter(splat))) {
match.params[splat] = remainder;
} else {
return null;
}
}
return match;
};
}
function matchSegment(input, filter) {
const isEqual = s => s === input;
if (filter === undefined) {
return true;
} else if (typeof filter === "string") {
return isEqual(filter);
} else if (typeof filter === "function") {
return filter(input);
} else if (Array.isArray(filter)) {
return filter.some(isEqual);
} else if (filter instanceof RegExp) {
return filter.test(input);
}
return false;
}
function scoreRoute(route) {
const [pattern, splat] = route.pattern.split("/*", 2);
const segments = pattern.split("/").filter(Boolean);
return segments.reduce((score, segment) => score + (segment.startsWith(":") ? 2 : 3), segments.length - (splat === undefined ? 0 : 1));
}
function createMemoObject(fn) {
const map = new Map();
const owner = getOwner();
return new Proxy({}, {
get(_, property) {
if (!map.has(property)) {
runWithOwner(owner, () => map.set(property, createMemo(() => fn()[property])));
}
return map.get(property)();
},
getOwnPropertyDescriptor() {
return {
enumerable: true,
configurable: true
};
},
ownKeys() {
return Reflect.ownKeys(fn());
},
has(_, property) {
return property in fn();
}
});
}
function mergeSearchString(search, params) {
const merged = new URLSearchParams(search);
Object.entries(params).forEach(([key, value]) => {
if (value == null || value === "" || value instanceof Array && !value.length) {
merged.delete(key);
} else {
if (value instanceof Array) {
// Delete all instances of the key before appending
merged.delete(key);
value.forEach(v => {
merged.append(key, String(v));
});
} else {
merged.set(key, String(value));
}
}
});
const s = merged.toString();
return s ? `?${s}` : "";
}
function expandOptionals(pattern) {
let match = /(\/?\:[^\/]+)\?/.exec(pattern);
if (!match) return [pattern];
let prefix = pattern.slice(0, match.index);
let suffix = pattern.slice(match.index + match[0].length);
const prefixes = [prefix, prefix += match[1]];
// This section handles adjacent optional params. We don't actually want all permuations since
// that will lead to equivalent routes which have the same number of params. For example
// `/:a?/:b?/:c`? only has the unique expansion: `/`, `/:a`, `/:a/:b`, `/:a/:b/:c` and we can
// discard `/:b`, `/:c`, `/:b/:c` by building them up in order and not recursing. This also helps
// ensure predictability where earlier params have precidence.
while (match = /^(\/\:[^\/]+)\?/.exec(suffix)) {
prefixes.push(prefix += match[1]);
suffix = suffix.slice(match[0].length);
}
return expandOptionals(suffix).reduce((results, expansion) => [...results, ...prefixes.map(p => p + expansion)], []);
}
function setFunctionName(obj, value) {
Object.defineProperty(obj, "name", {
value,
writable: false,
configurable: false
});
return obj;
}
const MAX_REDIRECTS = 100;
/** Consider this API opaque and internal. It is likely to change in the future. */
const RouterContextObj = createContext();
const RouteContextObj = createContext();
const useRouter = () => invariant(useContext(RouterContextObj), "<A> and 'use' router primitives can be only used inside a Route.");
const useRoute = () => useContext(RouteContextObj) || useRouter().base;
const useResolvedPath = path => {
const route = useRoute();
return createMemo(() => route.resolvePath(path()));
};
const useHref = to => {
const router = useRouter();
return createMemo(() => {
const to_ = to();
return to_ !== undefined ? router.renderPath(to_) : to_;
});
};
/**
* Retrieves method to do navigation. The method accepts a path to navigate to and an optional object with the following options:
*
* - resolve (*boolean*, default `true`): resolve the path against the current route
* - replace (*boolean*, default `false`): replace the history entry
* - scroll (*boolean*, default `true`): scroll to top after navigation
* - state (*any*, default `undefined`): pass custom state to `location.state`
*
* **Note**: The state is serialized using the structured clone algorithm which does not support all object types.
*
* @example
* ```js
* const navigate = useNavigate();
*
* if (unauthorized) {
* navigate("/login", { replace: true });
* }
* ```
*/
const useNavigate = () => useRouter().navigatorFactory();
/**
* Retrieves reactive `location` object useful for getting things like `pathname`.
*
* @example
* ```js
* const location = useLocation();
*
* const pathname = createMemo(() => parsePath(location.pathname));
* ```
*/
const useLocation = () => useRouter().location;
/**
* Retrieves signal that indicates whether the route is currently in a *Transition*.
* Useful for showing stale/pending state when the route resolution is *Suspended* during concurrent rendering.
*
* @example
* ```js
* const isRouting = useIsRouting();
*
* return (
* <div classList={{ "grey-out": isRouting() }}>
* <MyAwesomeContent />
* </div>
* );
* ```
*/
const useIsRouting = () => useRouter().isRouting;
/**
* usePreloadRoute returns a function that can be used to preload a route manual.
* This is what happens automatically with link hovering and similar focus based behavior, but it is available here as an API.
*
* @example
* ```js
* const preload = usePreloadRoute();
*
* preload(`/users/settings`, { preloadData: true });
* ```
*/
const usePreloadRoute = () => {
const pre = useRouter().preloadRoute;
return (url, options = {}) => pre(url instanceof URL ? url : new URL(url, mockBase), options.preloadData);
};
/**
* `useMatch` takes an accessor that returns the path and creates a `Memo` that returns match information if the current path matches the provided path.
* Useful for determining if a given path matches the current route.
*
* @example
* ```js
* const match = useMatch(() => props.href);
*
* return <div classList={{ active: Boolean(match()) }} />;
* ```
*/
const useMatch = (path, matchFilters) => {
const location = useLocation();
const matchers = createMemo(() => expandOptionals(path()).map(path => createMatcher(path, undefined, matchFilters)));
return createMemo(() => {
for (const matcher of matchers()) {
const match = matcher(location.pathname);
if (match) return match;
}
});
};
/**
* `useCurrentMatches` returns all the matches for the current matched route.
* Useful for getting all the route information.
*
* @example
* ```js
* const matches = useCurrentMatches();
*
* const breadcrumbs = createMemo(() => matches().map(m => m.route.info.breadcrumb))
* ```
*/
const useCurrentMatches = () => useRouter().matches;
/**
* Retrieves a reactive, store-like object containing the current route path parameters as defined in the Route.
*
* @example
* ```js
* const params = useParams();
*
* // fetch user based on the id path parameter
* const [user] = createResource(() => params.id, fetchUser);
* ```
*/
const useParams = () => useRouter().params;
/**
* Retrieves a tuple containing a reactive object to read the current location's query parameters and a method to update them.
* The object is a proxy so you must access properties to subscribe to reactive updates.
* **Note** that values will be strings and property names will retain their casing.
*
* The setter method accepts an object whose entries will be merged into the current query string.
* Values `''`, `undefined` and `null` will remove the key from the resulting query string.
* Updates will behave just like a navigation and the setter accepts the same optional second parameter as `navigate` and auto-scrolling is disabled by default.
*
* @examples
* ```js
* const [searchParams, setSearchParams] = useSearchParams();
*
* return (
* <div>
* <span>Page: {searchParams.page}</span>
* <button
* onClick={() =>
* setSearchParams({ page: (parseInt(searchParams.page) || 0) + 1 })
* }
* >
* Next Page
* </button>
* </div>
* );
* ```
*/
const useSearchParams = () => {
const location = useLocation();
const navigate = useNavigate();
const setSearchParams = (params, options) => {
const searchString = untrack(() => mergeSearchString(location.search, params) + location.hash);
navigate(searchString, {
scroll: false,
resolve: false,
...options
});
};
return [location.query, setSearchParams];
};
/**
* useBeforeLeave takes a function that will be called prior to leaving a route.
* The function will be called with:
*
* - from (*Location*): current location (before change).
* - to (*string | number*): path passed to `navigate`.
* - options (*NavigateOptions*): options passed to navigate.
* - preventDefault (*function*): call to block the route change.
* - defaultPrevented (*readonly boolean*): `true` if any previously called leave handlers called `preventDefault`.
* - retry (*function*, force?: boolean ): call to retry the same navigation, perhaps after confirming with the user. Pass `true` to skip running the leave handlers again (i.e. force navigate without confirming).
*
* @example
* ```js
* useBeforeLeave((e: BeforeLeaveEventArgs) => {
* if (form.isDirty && !e.defaultPrevented) {
* // preventDefault to block immediately and prompt user async
* e.preventDefault();
* setTimeout(() => {
* if (window.confirm("Discard unsaved changes - are you sure?")) {
* // user wants to proceed anyway so retry with force=true
* e.retry(true);
* }
* }, 100);
* }
* });
* ```
*/
const useBeforeLeave = listener => {
const s = useRouter().beforeLeave.subscribe({
listener,
location: useLocation(),
navigate: useNavigate()
});
onCleanup(s);
};
function createRoutes(routeDef, base = "") {
const {
component,
preload,
load,
children,
info
} = routeDef;
const isLeaf = !children || Array.isArray(children) && !children.length;
const shared = {
key: routeDef,
component,
preload: preload || load,
info
};
return asArray(routeDef.path).reduce((acc, originalPath) => {
for (const expandedPath of expandOptionals(originalPath)) {
const path = joinPaths(base, expandedPath);
let pattern = isLeaf ? path : path.split("/*", 1)[0];
pattern = pattern.split("/").map(s => {
return s.startsWith(":") || s.startsWith("*") ? s : encodeURIComponent(s);
}).join("/");
acc.push({
...shared,
originalPath,
pattern,
matcher: createMatcher(pattern, !isLeaf, routeDef.matchFilters)
});
}
return acc;
}, []);
}
function createBranch(routes, index = 0) {
return {
routes,
score: scoreRoute(routes[routes.length - 1]) * 10000 - index,
matcher(location) {
const matches = [];
for (let i = routes.length - 1; i >= 0; i--) {
const route = routes[i];
const match = route.matcher(location);
if (!match) {
return null;
}
matches.unshift({
...match,
route
});
}
return matches;
}
};
}
function asArray(value) {
return Array.isArray(value) ? value : [value];
}
function createBranches(routeDef, base = "", stack = [], branches = []) {
const routeDefs = asArray(routeDef);
for (let i = 0, len = routeDefs.length; i < len; i++) {
const def = routeDefs[i];
if (def && typeof def === "object") {
if (!def.hasOwnProperty("path")) def.path = "";
const routes = createRoutes(def, base);
for (const route of routes) {
stack.push(route);
const isEmptyArray = Array.isArray(def.children) && def.children.length === 0;
if (def.children && !isEmptyArray) {
createBranches(def.children, route.pattern, stack, branches);
} else {
const branch = createBranch([...stack], branches.length);
branches.push(branch);
}
stack.pop();
}
}
}
// Stack will be empty on final return
return stack.length ? branches : branches.sort((a, b) => b.score - a.score);
}
function getRouteMatches(branches, location) {
for (let i = 0, len = branches.length; i < len; i++) {
const match = branches[i].matcher(location);
if (match) {
return match;
}
}
return [];
}
function createLocation(path, state, queryWrapper) {
const origin = new URL(mockBase);
const url = createMemo(prev => {
const path_ = path();
try {
return new URL(path_, origin);
} catch (err) {
console.error(`Invalid path ${path_}`);
return prev;
}
}, origin, {
equals: (a, b) => a.href === b.href
});
const pathname = createMemo(() => url().pathname);
const search = createMemo(() => url().search, true);
const hash = createMemo(() => url().hash);
const key = () => "";
const queryFn = on(search, () => extractSearchParams(url()));
return {
get pathname() {
return pathname();
},
get search() {
return search();
},
get hash() {
return hash();
},
get state() {
return state();
},
get key() {
return key();
},
query: queryWrapper ? queryWrapper(queryFn) : createMemoObject(queryFn)
};
}
let intent;
function getIntent() {
return intent;
}
let inPreloadFn = false;
function getInPreloadFn() {
return inPreloadFn;
}
function setInPreloadFn(value) {
inPreloadFn = value;
}
function createRouterContext(integration, branches, getContext, options = {}) {
const {
signal: [source, setSource],
utils = {}
} = integration;
const parsePath = utils.parsePath || (p => p);
const renderPath = utils.renderPath || (p => p);
const beforeLeave = utils.beforeLeave || createBeforeLeave();
const basePath = resolvePath("", options.base || "");
if (basePath === undefined) {
throw new Error(`${basePath} is not a valid base path`);
} else if (basePath && !source().value) {
setSource({
value: basePath,
replace: true,
scroll: false
});
}
const [isRouting, setIsRouting] = createSignal(false);
// Keep track of last target, so that last call to transition wins
let lastTransitionTarget;
// Transition the location to a new value
const transition = (newIntent, newTarget) => {
if (newTarget.value === reference() && newTarget.state === state()) return;
if (lastTransitionTarget === undefined) setIsRouting(true);
intent = newIntent;
lastTransitionTarget = newTarget;
startTransition(() => {
if (lastTransitionTarget !== newTarget) return;
setReference(lastTransitionTarget.value);
setState(lastTransitionTarget.state);
resetErrorBoundaries();
if (!isServer) submissions[1](subs => subs.filter(s => s.pending));
}).finally(() => {
if (lastTransitionTarget !== newTarget) return;
// Batch, in order for isRouting and final source update to happen together
batch(() => {
intent = undefined;
if (newIntent === "navigate") navigateEnd(lastTransitionTarget);
setIsRouting(false);
lastTransitionTarget = undefined;
});
});
};
const [reference, setReference] = createSignal(source().value);
const [state, setState] = createSignal(source().state);
const location = createLocation(reference, state, utils.queryWrapper);
const referrers = [];
const submissions = createSignal(isServer ? initFromFlash() : []);
const matches = createMemo(() => {
if (typeof options.transformUrl === "function") {
return getRouteMatches(branches(), options.transformUrl(location.pathname));
}
return getRouteMatches(branches(), location.pathname);
});
const buildParams = () => {
const m = matches();
const params = {};
for (let i = 0; i < m.length; i++) {
Object.assign(params, m[i].params);
}
return params;
};
const params = utils.paramsWrapper ? utils.paramsWrapper(buildParams, branches) : createMemoObject(buildParams);
const baseRoute = {
pattern: basePath,
path: () => basePath,
outlet: () => null,
resolvePath(to) {
return resolvePath(basePath, to);
}
};
// Create a native transition, when source updates
createRenderEffect(on(source, source => transition("native", source), {
defer: true
}));
return {
base: baseRoute,
location,
params,
isRouting,
renderPath,
parsePath,
navigatorFactory,
matches,
beforeLeave,
preloadRoute,
singleFlight: options.singleFlight === undefined ? true : options.singleFlight,
submissions
};
function navigateFromRoute(route, to, options) {
// Untrack in case someone navigates in an effect - don't want to track `reference` or route paths
untrack(() => {
if (typeof to === "number") {
if (!to) ; else if (utils.go) {
utils.go(to);
} else {
console.warn("Router integration does not support relative routing");
}
return;
}
const queryOnly = !to || to[0] === "?";
const {
replace,
resolve,
scroll,
state: nextState
} = {
replace: false,
resolve: !queryOnly,
scroll: true,
...options
};
const resolvedTo = resolve ? route.resolvePath(to) : resolvePath(queryOnly && location.pathname || "", to);
if (resolvedTo === undefined) {
throw new Error(`Path '${to}' is not a routable path`);
} else if (referrers.length >= MAX_REDIRECTS) {
throw new Error("Too many redirects");
}
const current = reference();
if (resolvedTo !== current || nextState !== state()) {
if (isServer) {
const e = getRequestEvent();
e && (e.response = {
status: 302,
headers: new Headers({
Location: resolvedTo
})
});
setSource({
value: resolvedTo,
replace,
scroll,
state: nextState
});
} else if (beforeLeave.confirm(resolvedTo, options)) {
referrers.push({
value: current,
replace,
scroll,
state: state()
});
transition("navigate", {
value: resolvedTo,
state: nextState
});
}
}
});
}
function navigatorFactory(route) {
// Workaround for vite issue (https://github.com/vitejs/vite/issues/3803)
route = route || useContext(RouteContextObj) || baseRoute;
return (to, options) => navigateFromRoute(route, to, options);
}
function navigateEnd(next) {
const first = referrers[0];
if (first) {
setSource({
...next,
replace: first.replace,
scroll: first.scroll
});
referrers.length = 0;
}
}
function preloadRoute(url, preloadData) {
const matches = getRouteMatches(branches(), url.pathname);
const prevIntent = intent;
intent = "preload";
for (let match in matches) {
const {
route,
params
} = matches[match];
route.component && route.component.preload && route.component.preload();
const {
preload
} = route;
inPreloadFn = true;
preloadData && preload && runWithOwner(getContext(), () => preload({
params,
location: {
pathname: url.pathname,
search: url.search,
hash: url.hash,
query: extractSearchParams(url),
state: null,
key: ""
},
intent: "preload"
}));
inPreloadFn = false;
}
intent = prevIntent;
}
function initFromFlash() {
const e = getRequestEvent();
return e && e.router && e.router.submission ? [e.router.submission] : [];
}
}
function createRouteContext(router, parent, outlet, match) {
const {
base,
location,
params
} = router;
const {
pattern,
component,
preload
} = match().route;
const path = createMemo(() => match().path);
component && component.preload && component.preload();
inPreloadFn = true;
const data = preload ? preload({
params,
location,
intent: intent || "initial"
}) : undefined;
inPreloadFn = false;
const route = {
parent,
pattern,
path,
outlet: () => component ? createComponent(component, {
params,
location,
data,
get children() {
return outlet();
}
}) : outlet(),
resolvePath(to) {
return resolvePath(base.path(), to, path());
}
};
return route;
}
const createRouterComponent = router => props => {
const {
base
} = props;
const routeDefs = children(() => props.children);
const branches = createMemo(() => createBranches(routeDefs(), props.base || ""));
let context;
const routerState = createRouterContext(router, branches, () => context, {
base,
singleFlight: props.singleFlight,
transformUrl: props.transformUrl
});
router.create && router.create(routerState);
return createComponent$1(RouterContextObj.Provider, {
value: routerState,
get children() {
return createComponent$1(Root, {
routerState: routerState,
get root() {
return props.root;
},
get preload() {
return props.rootPreload || props.rootLoad;
},
get children() {
return [memo(() => (context = getOwner()) && null), createComponent$1(Routes, {
routerState: routerState,
get branches() {
return branches();
}
})];
}
});
}
});
};
function Root(props) {
const location = props.routerState.location;
const params = props.routerState.params;
const data = createMemo(() => props.preload && untrack(() => {
setInPreloadFn(true);
props.preload({
params,
location,
intent: getIntent() || "initial"
});
setInPreloadFn(false);
}));
return createComponent$1(Show, {
get when() {
return props.root;
},
keyed: true,
get fallback() {
return props.children;
},
children: Root => createComponent$1(Root, {
params: params,
location: location,
get data() {
return data();
},
get children() {
return props.children;
}
})
});
}
function Routes(props) {
if (isServer) {
const e = getRequestEvent();
if (e && e.router && e.router.dataOnly) {
dataOnly(e, props.routerState, props.branches);
return;
}
e && ((e.router || (e.router = {})).matches || (e.router.matches = props.routerState.matches().map(({
route,
path,
params
}) => ({
path: route.originalPath,
pattern: route.pattern,
match: path,
params,
info: route.info
}))));
}
const disposers = [];
let root;
const routeStates = createMemo(on(props.routerState.matches, (nextMatches, prevMatches, prev) => {
let equal = prevMatches && nextMatches.length === prevMatches.length;
const next = [];
for (let i = 0, len = nextMatches.length; i < len; i++) {
const prevMatch = prevMatches && prevMatches[i];
const nextMatch = nextMatches[i];
if (prev && prevMatch && nextMatch.route.key === prevMatch.route.key) {
next[i] = prev[i];
} else {
equal = false;
if (disposers[i]) {
disposers[i]();
}
createRoot(dispose => {
disposers[i] = dispose;
next[i] = createRouteContext(props.routerState, next[i - 1] || props.routerState.base, createOutlet(() => routeStates()[i + 1]), () => {
const routeMatches = props.routerState.matches();
return routeMatches[i] ?? routeMatches[0];
});
});
}
}
disposers.splice(nextMatches.length).forEach(dispose => dispose());
if (prev && equal) {
return prev;
}
root = next[0];
return next;
}));
return createOutlet(() => routeStates() && root)();
}
const createOutlet = child => {
return () => createComponent$1(Show, {
get when() {
return child();
},
keyed: true,
children: child => createComponent$1(RouteContextObj.Provider, {
value: child,
get children() {
return child.outlet();
}
})
});
};
const Route = props => {
const childRoutes = children(() => props.children);
return mergeProps(props, {
get children() {
return childRoutes();
}
});
};
// for data only mode with single flight mutations
function dataOnly(event, routerState, branches) {
const url = new URL(event.request.url);
const prevMatches = getRouteMatches(branches, new URL(event.router.previousUrl || event.request.url).pathname);
const matches = getRouteMatches(branches, url.pathname);
for (let match = 0; match < matches.length; match++) {
if (!prevMatches[match] || matches[match].route !== prevMatches[match].route) event.router.dataOnly = true;
const {
route,
params
} = matches[match];
route.preload && route.preload({
params,
location: routerState.location,
intent: "preload"
});
}
}
function intercept([value, setValue], get, set) {
return [value, set ? v => setValue(set(v)) : setValue];
}
function createRouter(config) {
let ignore = false;
const wrap = value => typeof value === "string" ? {
value
} : value;
const signal = intercept(createSignal(wrap(config.get()), {
equals: (a, b) => a.value === b.value && a.state === b.state
}), undefined, next => {
!ignore && config.set(next);
if (sharedConfig.registry && !sharedConfig.done) sharedConfig.done = true;
return next;
});
config.init && onCleanup(config.init((value = config.get()) => {
ignore = true;
signal[1](wrap(value));
ignore = false;
}));
return createRouterComponent({
signal,
create: config.create,
utils: config.utils
});
}
function bindEvent(target, type, handler) {
target.addEventListener(type, handler);
return () => target.removeEventListener(type, handler);
}
function scrollToHash(hash, fallbackTop) {
const el = hash && document.getElementById(hash);
if (el) {
el.scrollIntoView();
} else if (fallbackTop) {
window.scrollTo(0, 0);
}
}
function getPath(url) {
const u = new URL(url);
return u.pathname + u.search;
}
function StaticRouter(props) {
let e;
const obj = {
value: props.url || (e = getRequestEvent()) && getPath(e.request.url) || ""
};
return createRouterComponent({
signal: [() => obj, next => Object.assign(obj, next)]
})(props);
}
const LocationHeader = "Location";
const PRELOAD_TIMEOUT = 5000;
const CACHE_TIMEOUT = 180000;
let cacheMap = new Map();
// cleanup forward/back cache
if (!isServer) {
setInterval(() => {
const now = Date.now();
for (let [k, v] of cacheMap.entries()) {
if (!v[4].count && now - v[0] > CACHE_TIMEOUT) {
cacheMap.delete(k);
}
}
}, 300000);
}
function getCache() {
if (!isServer) return cacheMap;
const req = getRequestEvent();
if (!req) throw new Error("Cannot find cache context");
return (req.router || (req.router = {})).cache || (req.router.cache = new Map());
}
/**
* Revalidates the given cache entry/entries.
*/
function revalidate(key, force = true) {
return startTransition(() => {
const now = Date.now();
cacheKeyOp(key, entry => {
force && (entry[0] = 0); //force cache miss
entry[4][1](now); // retrigger live signals
});
});
}
function cacheKeyOp(key, fn) {
key && !Array.isArray(key) && (key = [key]);
for (let k of cacheMap.keys()) {
if (key === undefined || matchKey(k, key)) fn(cacheMap.get(k));
}
}
function query(fn, name) {
// prioritize GET for server functions
if (fn.GET) fn = fn.GET;
const cachedFn = (...args) => {
const cache = getCache();
const intent = getIntent();
const inPreloadFn = getInPreloadFn();
const owner = getOwner();
const navigate = owner ? useNavigate() : undefined;
const now = Date.now();
const key = name + hashKey(args);
let cached = cache.get(key);
let tracking;
if (isServer) {
const e = getRequestEvent();
if (e) {
const dataOnly = (e.router || (e.router = {})).dataOnly;
if (dataOnly) {
const data = e && (e.router.data || (e.router.data = {}));
if (data && key in data) return data[key];
if (Array.isArray(dataOnly) && !matchKey(key, dataOnly)) {
data[key] = undefined;
return Promise.resolve();
}
}
}
}
if (getListener() && !isServer) {
tracking = true;
onCleanup(() => cached[4].count--);
}
if (cached && cached[0] && (isServer || intent === "native" || cached[4].count || Date.now() - cached[0] < PRELOAD_TIMEOUT)) {
if (tracking) {
cached[4].count++;
cached[4][0](); // track
}
if (cached[3] === "preload" && intent !== "preload") {
cached[0] = now;
}
let res = cached[1];
if (intent !== "preload") {
res = "then" in cached[1] ? cached[1].then(handleResponse(false), handleResponse(true)) : handleResponse(false)(cached[1]);
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
}
inPreloadFn && "then" in res && res.catch(() => {});
return res;
}
let res;
if (!isServer && sharedConfig.has && sharedConfig.has(key)) {
res = sharedConfig.load(key); // hydrating
// @ts-ignore at least until we add a delete method to sharedConfig
delete globalThis._$HY.r[key];
} else res = fn(...args);
if (cached) {
cached[0] = now;
cached[1] = res;
cached[3] = intent;
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version
} else {
cache.set(key, cached = [now, res,, intent, createSignal(now)]);
cached[4].count = 0;
}
if (tracking) {
cached[4].count++;
cached[4][0](); // track
}
if (isServer) {
const e = getRequestEvent();
if (e && e.router.dataOnly) return e.router.data[key] = res;
}
if (intent !== "preload") {
res = "then" in res ? res.then(handleResponse(false), handleResponse(true)) : handleResponse(false)(res);
}
inPreloadFn && "then" in res && res.catch(() => {});
// serialize on server
if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) {
const e = getRequestEvent();
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
}
return res;
function handleResponse(error) {
return async v => {
if (v instanceof Response) {
const e = getRequestEvent();
if (e) {
for (const [key, value] of v.headers) {
if (key == "set-cookie") e.response.headers.append("set-cookie", value);else e.response.headers.set(key, value);
}
}
const url = v.headers.get(LocationHeader);
if (url !== null) {
// client + server relative redirect
if (navigate && url.startsWith("/")) startTransition(() => {
navigate(url, {
replace: true
});
});else if (!isServer) window.location.href = url;else if (e) e.response.status = 302;
return;
}
if (v.customBody) v = await v.customBody();
}
if (error) throw v;
cached[2] = v;
return v;
};
}
};
cachedFn.keyFor = (...args) => name + hashKey(args);
cachedFn.key = name;
return cachedFn;
}
query.get = key => {
const cached = getCache().get(key);
return cached[2];
};
query.set = (key, value) => {
const cache = getCache();
const now = Date.now();
let cached = cache.get(key);
if (cached) {
cached[0] = now;
cached[1] = Promise.resolve(value);
cached[2] = value;
cached[3] = "preload";
} else {
cache.set(key, cached = [now, Promise.resolve(value), value, "preload", createSignal(now)]);
cached[4].count = 0;
}
};
query.delete = key => getCache().delete(key);
query.clear = () => getCache().clear();
/** @deprecated use query instead */
const cache = query;
function matchKey(key, keys) {
for (let k of keys) {
if (k && key.startsWith(k)) return true;
}
return false;
}
// Modified from the amazing Tanstack Query library (MIT)
// https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L168
function hashKey(args) {
return JSON.stringify(args, (_, val) => isPlainObject(val) ? Object.keys(val).sort().reduce((result, key) => {
result[key] = val[key];
return result;
}, {}) : val);
}
function isPlainObject(obj) {
let proto;
return obj != null && typeof obj === "object" && (!(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype);
}
const actions = /* #__PURE__ */new Map();
function useSubmissions(fn, filter) {
const router = useRouter();
const subs = createMemo(() => router.submissions[0]().filter(s => s.url === fn.base && (!filter || filter(s.input))));
return new Proxy([], {
get(_, property) {
if (property === $TRACK) return subs();
if (property === "pending") return subs().some(sub => !sub.result);
return subs()[property];
},
has(_, property) {
return property in subs();
}
});
}
function useSubmission(fn, filter) {
const submissions = useSubmissions(fn, filter);
return new Proxy({}, {
get(_, property) {
if (submissions.length === 0 && property === "clear" || property === "retry") return () => {};
return submissions[submissions.length - 1]?.[property];
}
});
}
function useAction(action) {
const r = useRouter();
return (...args) => action.apply({
r
}, args);
}
function action(fn, options = {}) {
function mutate(...variables) {
const router = this.r;
const form = this.f;
const p = (router.singleFlight && fn.withOptions ? fn.withOptions({
headers: {
"X-Single-Flight": "true"
}
}) : fn)(...variables);
const [result, setResult] = createSignal();
let submission;
function handler(error) {
return async res => {
const result = await handleResponse(res, error, router.navigatorFactory());
let retry = null;
o.onComplete?.({
...submission,
result: result?.data,
error: result?.error,
pending: false,
retry() {
return retry = submission.retry();
}
});
if (retry) return retry;
if (!result) return submission.clear();
setResult(result);
if (result.error && !form) throw result.error;
return result.data;
};
}
router.submissions[1](s => [...s, submission = {
input: variables,
url,
get result() {
return result()?.data;
},
get error() {
return result()?.error;
},
get pending() {
return !result();
},
clear() {
router.submissions[1](v => v.filter(i => i !== submission));
},
retry() {
setResult(undefined);
const p = fn(...variables);
return p.then(handler(), handler(true));
}
}]);
return p.then(handler(), handler(true));
}
const o = typeof options === "string" ? {
name: options
} : options;
const name = o.name || (!isServer ? String(hashString(fn.toString())) : undefined);
const url = fn.url || name && `https://action/${name}` || "";
mutate.base = url;
if (name) setFunctionName(mutate, name);
return toAction(mutate, url);
}
function toAction(fn, url) {
fn.toString = () => {
if (!url) throw new Error("Client Actions need explicit names if server rendered");
return url;
};
fn.with = function (...args) {
const newFn = function (...passedArgs) {
return fn.call(this, ...args, ...passedArgs);
};
newFn.base = fn.base;
const uri = new URL(url, mockBase);
uri.searchParams.set("args", hashKey(args));
return toAction(newFn, (uri.origin === "https://action" ? uri.origin : "") + uri.pathname + uri.search);
};
fn.url = url;
if (!isServer) {
actions.set(url, fn);
getOwner() && onCleanup(() => actions.delete(url));
}
return fn;
}
const hashString = s => s.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt(0) | 0, 0);
async function handleResponse(response, error, navigate) {
let data;
let custom;
let keys;
let flightKeys;
if (response instanceof Response) {
if (response.headers.has("X-Revalidate")) keys = response.headers.get("X-Revalidate").split(",");
if (response.customBody) {
data = custom = await response.customBody();
if (response.headers.has("X-Single-Flight")) {
data = data._$value;
delete custom._$value;
flightKeys = Object.keys(custom);
}
}
if (response.headers.has("Location")) {
const locationUrl = response.headers.get("Location") || "/";
if (locationUrl.startsWith("http")) {
window.location.href = locationUrl;
} else {
navigate(locationUrl);
}
}
} else if (error) return {
error: response
};else data = response;
// invalidate
cacheKeyOp(keys, entry => entry[0] = 0);
// set cache
flightKeys && flightKeys.forEach(k => query.set(k, custom[k]));
// trigger revalidation
await revalidate(keys, false);
return data != null ? {
data
} : undefined;
}
function setupNativeEvents({
preload = true,
explicitLinks = false,
actionBase = "/_server",
transformUrl
} = {}) {
return router => {
const basePath = router.base.path();
const navigateFromRoute = router.navigatorFactory(router.base);
let preloadTimeout;
let lastElement;
function isSvg(el) {
return el.namespaceURI === "http://www.w3.org/2000/svg";
}
function handleAnchor(evt) {
if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a || explicitLinks && !a.hasAttribute("link")) return;
const svg = isSvg(a);
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || !href && !a.hasAttribute("state")) return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || rel && rel.includes("external")) return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (url.origin !== window.location.origin || basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
return [a, url];
}
function handleAnchorClick(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
const to = router.parsePath(url.pathname + url.search + url.hash);
const state = a.getAttribute("state");
evt.preventDefault();
navigateFromRoute(to, {
resolve: false,
replace: a.hasAttribute("replace"),
scroll: !a.hasAttribute("noscroll"),
state: state ? JSON.parse(state) : undefined
});
}
function handleAnchorPreload(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
transformUrl && (url.pathname = transformUrl(url.pathname));
router.preloadRoute(url, a.getAttribute("preload") !== "false");
}
function handleAnchorMove(evt) {
clearTimeout(preloadTimeout);
const res = handleAnchor(evt);
if (!res) return lastElement = null;
const [a, url] = res;
if (lastElement === a) return;
transformUrl && (url.pathname = transformUrl(url.pathname));
preloadTimeout = setTimeout(() => {
router.preloadRoute(url, a.getAttribute("preload") !== "false");
lastElement = a;
}, 20);
}
function handleFormSubmit(evt) {
if (evt.defaultPrevented) return;
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.getAttribute("formaction") : evt.target.getAttribute("action");
if (!actionRef) return;
if (!actionRef.startsWith("https://action/")) {
// normalize server actions
const url = new URL(actionRef, mockBase);
actionRef = router.parsePath(url.pathname + url.search);
if (!actionRef.startsWith(actionBase)) return;
}
if (evt.target.method.toUpperCase() !== "POST") throw new Error("Only POST forms are supported for Actions");
const handler = actions.get(actionRef);
if (handler) {
evt.preventDefault();
const data = new FormData(evt.target, evt.submitter);
handler.call({
r: router,
f: evt.target
}, evt.target.enctype === "multipart/form-data" ? data : new URLSearchParams(data));
}
}
// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
if (preload) {
document.addEventListener("mousemove", handleAnchorMove, {
passive: true
});
document.addEventListener("focusin", handleAnchorPreload, {
passive: true
});
document.addEventListener("touchstart", handleAnchorPreload, {
passive: true
});
}
document.addEventListener("submit", handleFormSubmit);
onCleanup(() => {
document.removeEventListener("click", handleAnchorClick);
if (preload) {
document.removeEventListener("mousemove", handleAnchorMove);
document.removeEventListener("focusin", handleAnchorPreload);
document.removeEventListener("touchstart", handleAnchorPreload);
}
document.removeEventListener("submit", handleFormSubmit);
});
};
}
function Router(props) {
if (isServer) return StaticRouter(props);
const getSource = () => {
const url = window.location.pathname.replace(/^\/+/, "/") + window.location.search;
const state = window.history.state && window.history.state._depth && Object.keys(window.history.state).length === 1 ? undefined : window.history.state;
return {
value: url + window.location.hash,
state
};
};
const beforeLeave = createBeforeLeave();
return createRouter({
get: getSource,
set({
value,
replace,
scroll,
state
}) {
if (replace) {
window.history.replaceState(keepDepth(state), "", value);
} else {
window.history.pushState(state, "", value);
}
scrollToHash(decodeURIComponent(window.location.hash.slice(1)), scroll);
saveCurrentDepth();
},
init: notify => bindEvent(window, "popstate", notifyIfNotBlocked(notify, delta => {
if (delta) {
return !beforeLeave.confirm(delta);
} else {
const s = getSource();
return !beforeLeave.confirm(s.value, {
state: s.state
});
}
})),
create: setupNativeEvents({
preload: props.preload,
explicitLinks: props.explicitLinks,
actionBase: props.actionBase,
transformUrl: props.transformUrl
}),
utils: {
go: delta => window.history.go(delta),
beforeLeave
}
})(props);
}
function hashParser(str) {
const to = str.replace(/^.*?#/, "");
// Hash-only hrefs like `#foo` from plain anchors will come in as `/#foo` whereas a link to
// `/foo` will be `/#/foo`. Check if the to starts with a `/` and if not append it as a hash
// to the current path so we can handle these in-page anchors correctly.
if (!to.startsWith("/")) {
const [, path = "/"] = window.location.hash.split("#", 2);
return `${path}#${to}`;
}
return to;
}
function HashRouter(props) {
const getSource = () => window.location.hash.slice(1);
const beforeLeave = createBeforeLeave();
return createRouter({
get: getSource,
set({
value,
replace,
scroll,
state
}) {
if (replace) {
window.history.replaceState(keepDepth(state), "", "#" + value);
} else {
window.history.pushState(state, "", "#" + value);
}
const hashIndex = value.indexOf("#");
const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : "";
scrollToHash(hash, scroll);
saveCurrentDepth();
},
init: notify => bindEvent(window, "hashchange", notifyIfNotBlocked(notify, delta => !beforeLeave.confirm(delta && delta < 0 ? delta : getSource()))),
create: setupNativeEvents({
preload: props.preload,
explicitLinks: props.explicitLinks,
actionBase: props.actionBase
}),
utils: {
go: delta => window.history.go(delta),
renderPath: path => `#${path}`,
parsePath: hashParser,
beforeLeave
}
})(props);
}
function createMemoryHistory() {
const entries = ["/"];
let index = 0;
const listeners = [];
const go = n => {
// https://github.com/remix-run/react-router/blob/682810ca929d0e3c64a76f8d6e465196b7a2ac58/packages/router/history.ts#L245
index = Math.max(0, Math.min(index + n, entries.length - 1));
const value = entries[index];
listeners.forEach(listener => listener(value));
};
return {
get: () => entries[index],
set: ({
value,
scroll,
replace
}) => {
if (replace) {
entries[index] = value;
} else {
entries.splice(index + 1, entries.length - index, value);
index++;
}
listeners.forEach(listener => listener(value));
setTimeout(() => {
if (scroll) {
scrollToHash(value.split("#")[1] || "", true);
}
}, 0);
},
back: () => {
go(-1);
},
forward: () => {
go(1);
},
go,
listen: listener => {
listeners.push(listener);
return () => {
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
};
}
};
}
function MemoryRouter(props) {
const memoryHistory = props.history || createMemoryHistory();
return createRouter({
get: memoryHistory.get,
set: memoryHistory.set,
init: memoryHistory.listen,
create: setupNativeEvents({
preload: props.preload,
explicitLinks: props.explicitLinks,
actionBase: props.actionBase
}),
utils: {
go: memoryHistory.go
}
})(props);
}
var _tmpl$ = /*#__PURE__*/template(`<a>`);
function A(props) {
props = mergeProps({
inactiveClass: "inactive",
activeClass: "active"
}, props);
const [, rest] = splitProps(props, ["href", "state", "class", "activeClass", "inactiveClass", "end"]);
const to = useResolvedPath(() => props.href);
const href = useHref(to);
const location = useLocation();
const isActive = createMemo(() => {
const to_ = to();
if (to_ === undefined) return [false, false];
const path = normalizePath(to_.split(/[?#]/, 1)[0]).toLowerCase();
const loc = decodeURI(normalizePath(location.pathname).toLowerCase());
return [props.end ? path === loc : loc.startsWith(path + "/") || loc === path, path === loc];
});
return (() => {
var _el$ = _tmpl$();
spread(_el$, mergeProps$1(rest, {
get href() {
return href() || props.href;
},
get state() {
return JSON.stringify(props.state);
},
get classList() {
return {
...(props.class && {
[props.class]: true
}),
[props.inactiveClass]: !isActive()[0],
[props.activeClass]: isActive()[0],
...rest.classList
};
},
"link": "",
get ["aria-current"]() {
return isActive()[1] ? "page" : undefined;
}
}), false, false);
return _el$;
})();
}
function Navigate(props) {
const navigate = useNavigate();
const location = useLocation();
const {
href,
state
} = props;
const path = typeof href === "function" ? href({
navigate,
location
}) : href;
navigate(path, {
replace: true,
state
});
return null;
}
/**
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
*/
/**
* As `createAsync` and `createAsyncStore` are wrappers for `createResource`,
* this type allows to support `latest` field for these primitives.
* It will be removed in the future.
*/
function createAsync(fn, options) {
let resource;
let prev = () => !resource || resource.state === "unresolved" ? undefined : resource.latest;
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, options);
const resultAccessor = () => resource();
if (options?.name) setFunctionName(resultAccessor, options.name);
Object.defineProperty(resultAccessor, "latest", {
get() {
return resource.latest;
}
});
return resultAccessor;
}
function createAsyncStore(fn, options = {}) {
let resource;
let prev = () => !resource || resource.state === "unresolved" ? undefined : unwrap(resource.latest);
[resource] = createResource(() => subFetch(fn, catchError(() => untrack(prev), () => undefined)), v => v, {
...options,
storage: init => createDeepSignal(init, options.reconcile)
});
const resultAccessor = () => resource();
Object.defineProperty(resultAccessor, "latest", {
get() {
return resource.latest;
}
});
return resultAccessor;
}
function createDeepSignal(value, options) {
const [store, setStore] = createStore({
value: structuredClone(value)
});
return [() => store.value, v => {
typeof v === "function" && (v = v());
setStore("value", reconcile(structuredClone(v), options));
return store.value;
}];
}
// mock promise while hydrating to prevent fetching
class MockPromise {
static all() {
return new MockPromise();
}
static allSettled() {
return new MockPromise();
}
static any() {
return new MockPromise();
}
static race() {
return new MockPromise();
}
static reject() {
return new MockPromise();
}
static resolve() {
return new MockPromise();
}
catch() {
return new MockPromise();
}
then() {
return new MockPromise();
}
finally() {
return new MockPromise();
}
}
function subFetch(fn, prev) {
if (isServer || !sharedConfig.context) return fn(prev);
const ogFetch = fetch;
const ogPromise = Promise;
try {
window.fetch = () => new MockPromise();
Promise = MockPromise;
return fn(prev);
} finally {
window.fetch = ogFetch;
Promise = ogPromise;
}
}
function redirect(url, init = 302) {
let responseInit;
let revalidate;
if (typeof init === "number") {
responseInit = {
status: init
};
} else {
({
revalidate,
...responseInit
} = init);
if (typeof responseInit.status === "undefined") {
responseInit.status = 302;
}
}
const headers = new Headers(responseInit.headers);
headers.set("Location", url);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
const response = new Response(null, {
...responseInit,
headers: headers
});
return response;
}
function reload(init = {}) {
const {
revalidate,
...responseInit
} = init;
const headers = new Headers(responseInit.headers);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
return new Response(null, {
...responseInit,
headers
});
}
function json(data, init = {}) {
const {
revalidate,
...responseInit
} = init;
const headers = new Headers(responseInit.headers);
revalidate !== undefined && headers.set("X-Revalidate", revalidate.toString());
headers.set("Content-Type", "application/json");
const response = new Response(JSON.stringify(data), {
...responseInit,
headers
});
response.customBody = () => data;
return response;
}
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, RouterContextObj as RouterContext, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, query, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useCurrentMatches, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, usePreloadRoute, useResolvedPath, useSearchParams, useSubmission, useSubmissions };