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>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

21
node_modules/@solidjs/router/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020-2022 Ryan Carniato
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1038
node_modules/@solidjs/router/README.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

31
node_modules/@solidjs/router/dist/components.d.ts generated vendored Normal file
View File

@@ -0,0 +1,31 @@
import type { JSX } from "solid-js";
import type { Location, Navigator } from "./types.js";
declare module "solid-js" {
namespace JSX {
interface AnchorHTMLAttributes<T> {
state?: string;
noScroll?: boolean;
replace?: boolean;
preload?: boolean;
link?: boolean;
}
}
}
export interface AnchorProps extends Omit<JSX.AnchorHTMLAttributes<HTMLAnchorElement>, "state"> {
href: string;
replace?: boolean | undefined;
noScroll?: boolean | undefined;
state?: unknown | undefined;
inactiveClass?: string | undefined;
activeClass?: string | undefined;
end?: boolean | undefined;
}
export declare function A(props: AnchorProps): JSX.Element;
export interface NavigateProps {
href: ((args: {
navigate: Navigator;
location: Location;
}) => string) | string;
state?: unknown;
}
export declare function Navigate(props: NavigateProps): null;

39
node_modules/@solidjs/router/dist/components.jsx generated vendored Normal file
View File

@@ -0,0 +1,39 @@
import { createMemo, mergeProps, splitProps } from "solid-js";
import { useHref, useLocation, useNavigate, useResolvedPath } from "./routing.js";
import { normalizePath } from "./utils.js";
export 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 (<a {...rest} href={href() || props.href} state={JSON.stringify(props.state)} classList={{
...(props.class && { [props.class]: true }),
[props.inactiveClass]: !isActive()[0],
[props.activeClass]: isActive()[0],
...rest.classList
}} link aria-current={isActive()[1] ? "page" : undefined}/>);
}
export 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;
}

17
node_modules/@solidjs/router/dist/data/action.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import { JSX } from "solid-js";
import type { Submission, SubmissionStub, NarrowResponse } from "../types.js";
export type Action<T extends Array<any>, U, V = T> = (T extends [FormData | URLSearchParams] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<NarrowResponse<U>>) & {
url: string;
with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<NarrowResponse<U>>, ...args: A): Action<B, U, V>;
};
export declare const actions: Map<string, Action<any, any, any>>;
export declare function useSubmissions<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>>[] & {
pending: boolean;
};
export declare function useSubmission<T extends Array<any>, U, V>(fn: Action<T, U, V>, filter?: (input: V) => boolean): Submission<T, NarrowResponse<U>> | SubmissionStub;
export declare function useAction<T extends Array<any>, U, V>(action: Action<T, U, V>): (...args: Parameters<Action<T, U, V>>) => Promise<NarrowResponse<U>>;
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>;
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, options?: {
name?: string;
onComplete?: (s: Submission<T, U>) => void;
}): Action<T, U>;

163
node_modules/@solidjs/router/dist/data/action.js generated vendored Normal file
View File

@@ -0,0 +1,163 @@
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
import { isServer } from "solid-js/web";
import { useRouter } from "../routing.js";
import { mockBase, setFunctionName } from "../utils.js";
import { cacheKeyOp, hashKey, revalidate, query } from "./query.js";
export const actions = /* #__PURE__ */ new Map();
export 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();
}
});
}
export 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];
}
});
}
export function useAction(action) {
const r = useRouter();
return (...args) => action.apply({ r }, args);
}
export 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;
}

View File

@@ -0,0 +1,32 @@
import { type ReconcileOptions } from "solid-js/store";
/**
* 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.
*/
export type AccessorWithLatest<T> = {
(): T;
latest: T;
};
export declare function createAsync<T>(fn: (prev: T) => Promise<T>, options: {
name?: string;
initialValue: T;
deferStream?: boolean;
}): AccessorWithLatest<T>;
export declare function createAsync<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
name?: string;
initialValue?: T;
deferStream?: boolean;
}): AccessorWithLatest<T | undefined>;
export declare function createAsyncStore<T>(fn: (prev: T) => Promise<T>, options: {
name?: string;
initialValue: T;
deferStream?: boolean;
reconcile?: ReconcileOptions;
}): AccessorWithLatest<T>;
export declare function createAsyncStore<T>(fn: (prev: T | undefined) => Promise<T>, options?: {
name?: string;
initialValue?: T;
deferStream?: boolean;
reconcile?: ReconcileOptions;
}): AccessorWithLatest<T | undefined>;

96
node_modules/@solidjs/router/dist/data/createAsync.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
/**
* This is mock of the eventual Solid 2.0 primitive. It is not fully featured.
*/
import { createResource, sharedConfig, untrack, catchError } from "solid-js";
import { createStore, reconcile, unwrap } from "solid-js/store";
import { isServer } from "solid-js/web";
import { setFunctionName } from "../utils.js";
export 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;
}
export 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;
}
}

9
node_modules/@solidjs/router/dist/data/events.d.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import type { RouterContext } from "../types.js";
type NativeEventConfig = {
preload?: boolean;
explicitLinks?: boolean;
actionBase?: string;
transformUrl?: (url: string) => string;
};
export declare function setupNativeEvents({ preload, explicitLinks, actionBase, transformUrl }?: NativeEventConfig): (router: RouterContext) => void;
export {};

123
node_modules/@solidjs/router/dist/data/events.js generated vendored Normal file
View File

@@ -0,0 +1,123 @@
import { delegateEvents } from "solid-js/web";
import { onCleanup } from "solid-js";
import { actions } from "./action.js";
import { mockBase } from "../utils.js";
export 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);
});
};
}

4
node_modules/@solidjs/router/dist/data/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export { createAsync, createAsyncStore, type AccessorWithLatest } from "./createAsync.js";
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js";
export { query, revalidate, cache, type CachedFunction } from "./query.js";
export { redirect, reload, json } from "./response.js";

4
node_modules/@solidjs/router/dist/data/index.js generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export { createAsync, createAsyncStore } from "./createAsync.js";
export { action, useSubmission, useSubmissions, useAction } from "./action.js";
export { query, revalidate, cache } from "./query.js";
export { redirect, reload, json } from "./response.js";

23
node_modules/@solidjs/router/dist/data/query.d.ts generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import type { CacheEntry, NarrowResponse } from "../types.js";
/**
* Revalidates the given cache entry/entries.
*/
export declare function revalidate(key?: string | string[] | void, force?: boolean): Promise<void>;
export declare function cacheKeyOp(key: string | string[] | void, fn: (cacheEntry: CacheEntry) => void): void;
export type CachedFunction<T extends (...args: any) => any> = T extends (...args: infer A) => infer R ? ([] extends {
[K in keyof A]-?: A[K];
} ? (...args: never[]) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R> : (...args: A) => R extends Promise<infer P> ? Promise<NarrowResponse<P>> : NarrowResponse<R>) & {
keyFor: (...args: A) => string;
key: string;
} : never;
export declare function query<T extends (...args: any) => any>(fn: T, name: string): CachedFunction<T>;
export declare namespace query {
export var get: (key: string) => any;
export var set: <T>(key: string, value: T extends Promise<any> ? never : T) => void;
var _a: (key: string) => boolean;
export var clear: () => void;
export { _a as delete };
}
/** @deprecated use query instead */
export declare const cache: typeof query;
export declare function hashKey<T extends Array<any>>(args: T): string;

232
node_modules/@solidjs/router/dist/data/query.js generated vendored Normal file
View File

@@ -0,0 +1,232 @@
import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";
import { getRequestEvent, isServer } from "solid-js/web";
import { useNavigate, getIntent, getInPreloadFn } from "../routing.js";
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.
*/
export 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
});
});
}
export 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));
}
}
export 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 */
export 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
export 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));
}

4
node_modules/@solidjs/router/dist/data/response.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import type { RouterResponseInit, CustomResponse } from "../types.js";
export declare function redirect(url: string, init?: number | RouterResponseInit): CustomResponse<never>;
export declare function reload(init?: RouterResponseInit): CustomResponse<never>;
export declare function json<T>(data: T, init?: RouterResponseInit): CustomResponse<T>;

42
node_modules/@solidjs/router/dist/data/response.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
export 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;
}
export 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
});
}
export 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;
}

7
node_modules/@solidjs/router/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
export * from "./routers/index.js";
export * from "./components.jsx";
export * from "./lifecycle.js";
export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, usePreloadRoute, RouterContextObj as RouterContext } from "./routing.js";
export { mergeSearchString as _mergeSearchString } from "./utils.js";
export * from "./data/index.js";
export type { Location, LocationChange, SearchParams, MatchFilter, MatchFilters, NavigateOptions, Navigator, OutputMatch, Params, PathMatch, RouteSectionProps, RoutePreloadFunc, RoutePreloadFuncArgs, RouteDefinition, RouteDescription, RouteMatch, RouterIntegration, RouterUtils, SetParams, Submission, BeforeLeaveEventArgs, RouteLoadFunc, RouteLoadFuncArgs, RouterResponseInit, CustomResponse } from "./types.js";

1879
node_modules/@solidjs/router/dist/index.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

6
node_modules/@solidjs/router/dist/index.jsx generated vendored Normal file
View File

@@ -0,0 +1,6 @@
export * from "./routers/index.js";
export * from "./components.jsx";
export * from "./lifecycle.js";
export { useHref, useIsRouting, useLocation, useMatch, useCurrentMatches, useNavigate, useParams, useResolvedPath, useSearchParams, useBeforeLeave, usePreloadRoute, RouterContextObj as RouterContext } from "./routing.js";
export { mergeSearchString as _mergeSearchString } from "./utils.js";
export * from "./data/index.js";

5
node_modules/@solidjs/router/dist/lifecycle.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import { BeforeLeaveLifecycle, LocationChange } from "./types.js";
export declare function createBeforeLeave(): BeforeLeaveLifecycle;
export declare function saveCurrentDepth(): void;
export declare function keepDepth(state: any): any;
export declare function notifyIfNotBlocked(notify: (value?: string | LocationChange) => void, block: (delta: number | null) => boolean): () => void;

69
node_modules/@solidjs/router/dist/lifecycle.js generated vendored Normal file
View File

@@ -0,0 +1,69 @@
import { isServer } from "solid-js/web";
export 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;
export 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();
}
export function keepDepth(state) {
return {
...state,
_depth: window.history.state && window.history.state._depth
};
}
export 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();
}
};
}

View File

@@ -0,0 +1,9 @@
import type { JSX } from "solid-js";
import type { BaseRouterProps } from "./components.jsx";
export declare function hashParser(str: string): string;
export type HashRouterProps = BaseRouterProps & {
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function HashRouter(props: HashRouterProps): JSX.Element;

View File

@@ -0,0 +1,41 @@
import { setupNativeEvents } from "../data/events.js";
import { createRouter, scrollToHash, bindEvent } from "./createRouter.js";
import { createBeforeLeave, keepDepth, notifyIfNotBlocked, saveCurrentDepth } from "../lifecycle.js";
export 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;
}
export 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);
}

View File

@@ -0,0 +1,24 @@
import type { LocationChange } from "../types.js";
import type { BaseRouterProps } from "./components.jsx";
import type { JSX } from "solid-js";
export type MemoryHistory = {
get: () => string;
set: (change: LocationChange) => void;
go: (delta: number) => void;
listen: (listener: (value: string) => void) => () => void;
};
export declare function createMemoryHistory(): {
get: () => string;
set: ({ value, scroll, replace }: LocationChange) => void;
back: () => void;
forward: () => void;
go: (n: number) => void;
listen: (listener: (value: string) => void) => () => void;
};
export type MemoryRouterProps = BaseRouterProps & {
history?: MemoryHistory;
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function MemoryRouter(props: MemoryRouterProps): JSX.Element;

View File

@@ -0,0 +1,57 @@
import { createRouter, scrollToHash } from "./createRouter.js";
import { setupNativeEvents } from "../data/events.js";
export 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);
};
}
};
}
export 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);
}

View File

@@ -0,0 +1,9 @@
import type { BaseRouterProps } from "./components.jsx";
import type { JSX } from "solid-js";
export type RouterProps = BaseRouterProps & {
url?: string;
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function Router(props: RouterProps): JSX.Element;

45
node_modules/@solidjs/router/dist/routers/Router.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
import { isServer } from "solid-js/web";
import { createRouter, scrollToHash, bindEvent } from "./createRouter.js";
import { StaticRouter } from "./StaticRouter.js";
import { setupNativeEvents } from "../data/events.js";
import { createBeforeLeave, keepDepth, notifyIfNotBlocked, saveCurrentDepth } from "../lifecycle.js";
export 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);
}

View File

@@ -0,0 +1,6 @@
import { type BaseRouterProps } from "./components.jsx";
import type { JSX } from "solid-js";
export type StaticRouterProps = BaseRouterProps & {
url?: string;
};
export declare function StaticRouter(props: StaticRouterProps): JSX.Element;

View File

@@ -0,0 +1,15 @@
import { getRequestEvent } from "solid-js/web";
import { createRouterComponent } from "./components.jsx";
function getPath(url) {
const u = new URL(url);
return u.pathname + u.search;
}
export 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);
}

View File

@@ -0,0 +1,27 @@
import type { Component, JSX } from "solid-js";
import type { MatchFilters, RouteDefinition, RoutePreloadFunc, RouterIntegration, RouteSectionProps } from "../types.js";
export type BaseRouterProps = {
base?: string;
/**
* A component that wraps the content of every route.
*/
root?: Component<RouteSectionProps>;
rootPreload?: RoutePreloadFunc;
singleFlight?: boolean;
children?: JSX.Element | RouteDefinition | RouteDefinition[];
transformUrl?: (url: string) => string;
/** @deprecated use rootPreload */
rootLoad?: RoutePreloadFunc;
};
export declare const createRouterComponent: (router: RouterIntegration) => (props: BaseRouterProps) => JSX.Element;
export type RouteProps<S extends string, T = unknown> = {
path?: S | S[];
children?: JSX.Element;
preload?: RoutePreloadFunc<T>;
matchFilters?: MatchFilters<S>;
component?: Component<RouteSectionProps<T>>;
info?: Record<string, any>;
/** @deprecated use preload */
load?: RoutePreloadFunc<T>;
};
export declare const Route: <S extends string, T = unknown>(props: RouteProps<S, T>) => JSX.Element;

View File

@@ -0,0 +1,118 @@
/*@refresh skip*/
import { children, createMemo, createRoot, getOwner, mergeProps, on, Show, untrack } from "solid-js";
import { getRequestEvent, isServer } from "solid-js/web";
import { createBranches, createRouteContext, createRouterContext, getIntent, getRouteMatches, RouteContextObj, RouterContextObj, setInPreloadFn } from "../routing.js";
export 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 (<RouterContextObj.Provider value={routerState}>
<Root routerState={routerState} root={props.root} preload={props.rootPreload || props.rootLoad}>
{(context = getOwner()) && null}
<Routes routerState={routerState} branches={branches()}/>
</Root>
</RouterContextObj.Provider>);
};
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 (<Show when={props.root} keyed fallback={props.children}>
{Root => (<Root params={params} location={location} data={data()}>
{props.children}
</Root>)}
</Show>);
}
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 () => (<Show when={child()} keyed>
{child => <RouteContextObj.Provider value={child}>{child.outlet()}</RouteContextObj.Provider>}
</Show>);
};
export 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"
});
}
}

View File

@@ -0,0 +1,10 @@
import type { LocationChange, RouterContext, RouterUtils } from "../types.js";
export declare function createRouter(config: {
get: () => string | LocationChange;
set: (next: LocationChange) => void;
init?: (notify: (value?: string | LocationChange) => void) => () => void;
create?: (router: RouterContext) => void;
utils?: Partial<RouterUtils>;
}): (props: import("./components.jsx").BaseRouterProps) => import("solid-js").JSX.Element;
export declare function bindEvent(target: EventTarget, type: string, handler: EventListener): () => void;
export declare function scrollToHash(hash: string, fallbackTop?: boolean): void;

View File

@@ -0,0 +1,41 @@
import { createSignal, onCleanup, sharedConfig } from "solid-js";
import { createRouterComponent } from "./components.jsx";
function intercept([value, setValue], get, set) {
return [get ? () => get(value()) : value, set ? (v) => setValue(set(v)) : setValue];
}
export 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
});
}
export function bindEvent(target, type, handler) {
target.addEventListener(type, handler);
return () => target.removeEventListener(type, handler);
}
export function scrollToHash(hash, fallbackTop) {
const el = hash && document.getElementById(hash);
if (el) {
el.scrollIntoView();
}
else if (fallbackTop) {
window.scrollTo(0, 0);
}
}

11
node_modules/@solidjs/router/dist/routers/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
export { Route } from "./components.jsx";
export type { BaseRouterProps, RouteProps } from "./components.jsx";
export { createRouter } from "./createRouter.js";
export { Router } from "./Router.js";
export type { RouterProps } from "./Router.js";
export { HashRouter } from "./HashRouter.js";
export type { HashRouterProps } from "./HashRouter.js";
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter.js";
export type { MemoryRouterProps, MemoryHistory } from "./MemoryRouter.js";
export { StaticRouter } from "./StaticRouter.js";
export type { StaticRouterProps } from "./StaticRouter.js";

6
node_modules/@solidjs/router/dist/routers/index.js generated vendored Normal file
View File

@@ -0,0 +1,6 @@
export { Route } from "./components.jsx";
export { createRouter } from "./createRouter.js";
export { Router } from "./Router.js";
export { HashRouter } from "./HashRouter.js";
export { MemoryRouter, createMemoryHistory } from "./MemoryRouter.js";
export { StaticRouter } from "./StaticRouter.js";

175
node_modules/@solidjs/router/dist/routing.d.ts generated vendored Normal file
View File

@@ -0,0 +1,175 @@
import { JSX, Accessor } from "solid-js";
import type { BeforeLeaveEventArgs, Branch, Intent, Location, MatchFilters, NavigateOptions, Navigator, Params, RouteDescription, RouteContext, RouteDefinition, RouteMatch, RouterContext, RouterIntegration, SearchParams, SetSearchParams } from "./types.js";
/** Consider this API opaque and internal. It is likely to change in the future. */
export declare const RouterContextObj: import("solid-js").Context<RouterContext | undefined>;
export declare const RouteContextObj: import("solid-js").Context<RouteContext | undefined>;
export declare const useRouter: () => RouterContext;
export declare const useRoute: () => RouteContext;
export declare const useResolvedPath: (path: () => string) => Accessor<string | undefined>;
export declare const useHref: <T extends string | undefined>(to: () => T) => () => string | T;
/**
* 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 });
* }
* ```
*/
export declare const useNavigate: () => Navigator;
/**
* Retrieves reactive `location` object useful for getting things like `pathname`.
*
* @example
* ```js
* const location = useLocation();
*
* const pathname = createMemo(() => parsePath(location.pathname));
* ```
*/
export declare const useLocation: <S = unknown>() => Location<S>;
/**
* 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>
* );
* ```
*/
export declare const useIsRouting: () => () => boolean;
/**
* 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 });
* ```
*/
export declare const usePreloadRoute: () => (url: string | URL, options?: {
preloadData?: boolean;
}) => void;
/**
* `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()) }} />;
* ```
*/
export declare const useMatch: <S extends string>(path: () => S, matchFilters?: MatchFilters<S>) => Accessor<import("./types.js").PathMatch | undefined>;
/**
* `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))
* ```
*/
export declare const useCurrentMatches: () => () => RouteMatch[];
/**
* 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);
* ```
*/
export declare const useParams: <T extends Params>() => T;
/**
* 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>
* );
* ```
*/
export declare const useSearchParams: <T extends SearchParams>() => [Partial<T>, (params: SetSearchParams, options?: Partial<NavigateOptions>) => void];
/**
* 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);
* }
* });
* ```
*/
export declare const useBeforeLeave: (listener: (e: BeforeLeaveEventArgs) => void) => void;
export declare function createRoutes(routeDef: RouteDefinition, base?: string): RouteDescription[];
export declare function createBranch(routes: RouteDescription[], index?: number): Branch;
export declare function createBranches(routeDef: RouteDefinition | RouteDefinition[], base?: string, stack?: RouteDescription[], branches?: Branch[]): Branch[];
export declare function getRouteMatches(branches: Branch[], location: string): RouteMatch[];
export declare function getIntent(): Intent | undefined;
export declare function getInPreloadFn(): boolean;
export declare function setInPreloadFn(value: boolean): void;
export declare function createRouterContext(integration: RouterIntegration, branches: () => Branch[], getContext?: () => any, options?: {
base?: string;
singleFlight?: boolean;
transformUrl?: (url: string) => string;
}): RouterContext;
export declare function createRouteContext(router: RouterContext, parent: RouteContext, outlet: () => JSX.Element, match: () => RouteMatch): RouteContext;

560
node_modules/@solidjs/router/dist/routing.js generated vendored Normal file
View File

@@ -0,0 +1,560 @@
import { runWithOwner, batch } from "solid-js";
import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";
import { isServer, getRequestEvent } from "solid-js/web";
import { createBeforeLeave } from "./lifecycle.js";
import { mockBase, createMemoObject, extractSearchParams, invariant, resolvePath, createMatcher, joinPaths, scoreRoute, mergeSearchString, expandOptionals } from "./utils.js";
const MAX_REDIRECTS = 100;
/** Consider this API opaque and internal. It is likely to change in the future. */
export const RouterContextObj = createContext();
export const RouteContextObj = createContext();
export const useRouter = () => invariant(useContext(RouterContextObj), "<A> and 'use' router primitives can be only used inside a Route.");
let TempRoute;
export const useRoute = () => TempRoute || useContext(RouteContextObj) || useRouter().base;
export const useResolvedPath = (path) => {
const route = useRoute();
return createMemo(() => route.resolvePath(path()));
};
export 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 });
* }
* ```
*/
export 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));
* ```
*/
export 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>
* );
* ```
*/
export 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 });
* ```
*/
export 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()) }} />;
* ```
*/
export 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))
* ```
*/
export 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);
* ```
*/
export 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>
* );
* ```
*/
export 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);
* }
* });
* ```
*/
export const useBeforeLeave = (listener) => {
const s = useRouter().beforeLeave.subscribe({
listener,
location: useLocation(),
navigate: useNavigate()
});
onCleanup(s);
};
export 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;
}, []);
}
export 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];
}
export 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);
}
export 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;
export function getIntent() {
return intent;
}
let inPreloadFn = false;
export function getInPreloadFn() {
return inPreloadFn;
}
export function setInPreloadFn(value) {
inPreloadFn = value;
}
export 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) {
// A delta of 0 means stay at the current location, so it is ignored
}
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] : []);
}
}
export 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;
}

200
node_modules/@solidjs/router/dist/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,200 @@
import type { Component, JSX, Signal } from "solid-js";
declare module "solid-js/web" {
interface RequestEvent {
response: {
status?: number;
statusText?: string;
headers: Headers;
};
router?: {
matches?: OutputMatch[];
cache?: Map<string, CacheEntry>;
submission?: {
input: any;
result: any;
url: string;
};
dataOnly?: boolean | string[];
data?: Record<string, any>;
previousUrl?: string;
};
serverOnly?: boolean;
}
}
export type Params = Record<string, string | undefined>;
export type SearchParams = Record<string, string | string[] | undefined>;
export type SetParams = Record<string, string | number | boolean | null | undefined>;
export type SetSearchParams = Record<string, string | string[] | number | number[] | boolean | boolean[] | null | undefined>;
export interface Path {
pathname: string;
search: string;
hash: string;
}
export interface Location<S = unknown> extends Path {
query: SearchParams;
state: Readonly<Partial<S>> | null;
key: string;
}
export interface NavigateOptions<S = unknown> {
resolve: boolean;
replace: boolean;
scroll: boolean;
state: S;
}
export interface Navigator {
(to: string | number, options?: Partial<NavigateOptions>): void;
(delta: number): void;
}
export type NavigatorFactory = (route?: RouteContext) => Navigator;
export interface LocationChange<S = unknown> {
value: string;
replace?: boolean;
scroll?: boolean;
state?: S;
rawPath?: string;
}
export interface RouterIntegration {
signal: Signal<LocationChange>;
create?: (router: RouterContext) => void;
utils?: Partial<RouterUtils>;
}
export type Intent = "initial" | "native" | "navigate" | "preload";
export interface RoutePreloadFuncArgs {
params: Params;
location: Location;
intent: Intent;
}
export type RoutePreloadFunc<T = unknown> = (args: RoutePreloadFuncArgs) => T;
export interface RouteSectionProps<T = unknown> {
params: Params;
location: Location;
data: T;
children?: JSX.Element;
}
export type RouteDefinition<S extends string | string[] = any, T = unknown> = {
path?: S;
matchFilters?: MatchFilters<S>;
preload?: RoutePreloadFunc<T>;
children?: RouteDefinition | RouteDefinition[];
component?: Component<RouteSectionProps<T>>;
info?: Record<string, any>;
/** @deprecated use preload */
load?: RoutePreloadFunc;
};
export type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean);
export type PathParams<P extends string | readonly string[]> = P extends `${infer Head}/${infer Tail}` ? [...PathParams<Head>, ...PathParams<Tail>] : P extends `:${infer S}?` ? [S] : P extends `:${infer S}` ? [S] : P extends `*${infer S}` ? [S] : [];
export type MatchFilters<P extends string | readonly string[] = any> = P extends string ? {
[K in PathParams<P>[number]]?: MatchFilter;
} : Record<string, MatchFilter>;
export interface PathMatch {
params: Params;
path: string;
}
export interface RouteMatch extends PathMatch {
route: RouteDescription;
}
export interface OutputMatch {
path: string;
pattern: string;
match: string;
params: Params;
info?: Record<string, any>;
}
export interface RouteDescription {
key: unknown;
originalPath: string;
pattern: string;
component?: Component<RouteSectionProps>;
preload?: RoutePreloadFunc;
matcher: (location: string) => PathMatch | null;
matchFilters?: MatchFilters;
info?: Record<string, any>;
}
export interface Branch {
routes: RouteDescription[];
score: number;
matcher: (location: string) => RouteMatch[] | null;
}
export interface RouteContext {
parent?: RouteContext;
child?: RouteContext;
pattern: string;
path: () => string;
outlet: () => JSX.Element;
resolvePath(to: string): string | undefined;
}
export interface RouterUtils {
renderPath(path: string): string;
parsePath(str: string): string;
go(delta: number): void;
beforeLeave: BeforeLeaveLifecycle;
paramsWrapper: (getParams: () => Params, branches: () => Branch[]) => Params;
queryWrapper: (getQuery: () => SearchParams) => SearchParams;
}
export interface RouterContext {
base: RouteContext;
location: Location;
params: Params;
navigatorFactory: NavigatorFactory;
isRouting: () => boolean;
matches: () => RouteMatch[];
renderPath(path: string): string;
parsePath(str: string): string;
beforeLeave: BeforeLeaveLifecycle;
preloadRoute: (url: URL, preloadData?: boolean) => void;
singleFlight: boolean;
submissions: Signal<Submission<any, any>[]>;
}
export interface BeforeLeaveEventArgs {
from: Location;
to: string | number;
options?: Partial<NavigateOptions>;
readonly defaultPrevented: boolean;
preventDefault(): void;
retry(force?: boolean): void;
}
export interface BeforeLeaveListener {
listener(e: BeforeLeaveEventArgs): void;
location: Location;
navigate: Navigator;
}
export interface BeforeLeaveLifecycle {
subscribe(listener: BeforeLeaveListener): () => void;
confirm(to: string | number, options?: Partial<NavigateOptions>): boolean;
}
export type Submission<T, U> = {
readonly input: T;
readonly result?: U;
readonly error: any;
readonly pending: boolean;
readonly url: string;
clear: () => void;
retry: () => void;
};
export type SubmissionStub = {
readonly input: undefined;
readonly result: undefined;
readonly error: undefined;
readonly pending: undefined;
readonly url: undefined;
clear: () => void;
retry: () => void;
};
export interface MaybePreloadableComponent extends Component {
preload?: () => void;
}
export type CacheEntry = [number, Promise<any>, any, Intent | undefined, Signal<number> & {
count: number;
}];
export type NarrowResponse<T> = T extends CustomResponse<infer U> ? U : Exclude<T, Response>;
export type RouterResponseInit = Omit<ResponseInit, "body"> & {
revalidate?: string | string[];
};
export type CustomResponse<T> = Omit<Response, "clone"> & {
customBody: () => T;
clone(...args: readonly unknown[]): CustomResponse<T>;
};
/** @deprecated */
export type RouteLoadFunc = RoutePreloadFunc;
/** @deprecated */
export type RouteLoadFuncArgs = RoutePreloadFuncArgs;

1
node_modules/@solidjs/router/dist/types.js generated vendored Normal file
View File

@@ -0,0 +1 @@
export {};

13
node_modules/@solidjs/router/dist/utils.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import type { MatchFilters, PathMatch, RouteDescription, SearchParams, SetSearchParams } from "./types.js";
export declare const mockBase = "http://sr";
export declare function normalizePath(path: string, omitSlash?: boolean): string;
export declare function resolvePath(base: string, path: string, from?: string): string | undefined;
export declare function invariant<T>(value: T | null | undefined, message: string): T;
export declare function joinPaths(from: string, to: string): string;
export declare function extractSearchParams(url: URL): SearchParams;
export declare function createMatcher<S extends string>(path: S, partial?: boolean, matchFilters?: MatchFilters<S>): (location: string) => PathMatch | null;
export declare function scoreRoute(route: RouteDescription): number;
export declare function createMemoObject<T extends Record<string | symbol, unknown>>(fn: () => T): T;
export declare function mergeSearchString(search: string, params: SetSearchParams): string;
export declare function expandOptionals(pattern: string): string[];
export declare function setFunctionName<T>(obj: T, value: string): T;

185
node_modules/@solidjs/router/dist/utils.js generated vendored Normal file
View File

@@ -0,0 +1,185 @@
import { createMemo, getOwner, runWithOwner } from "solid-js";
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
const trimPathRegex = /^\/+|(\/)\/+$/g;
export const mockBase = "http://sr";
export function normalizePath(path, omitSlash = false) {
const s = path.replace(trimPathRegex, "$1");
return s ? (omitSlash || /^[?#]/.test(s) ? s : "/" + s) : "";
}
export 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);
}
export function invariant(value, message) {
if (value == null) {
throw new Error(message);
}
return value;
}
export function joinPaths(from, to) {
return normalizePath(from).replace(/\/*(\*.*)?$/g, "") + normalizePath(to);
}
export 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;
}
export 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;
}
export 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));
}
export 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();
}
});
}
export 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}` : "";
}
export 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)], []);
}
export function setFunctionName(obj, value) {
Object.defineProperty(obj, "name", {
value,
writable: false,
configurable: false
});
return obj;
}

61
node_modules/@solidjs/router/package.json generated vendored Normal file
View File

@@ -0,0 +1,61 @@
{
"name": "@solidjs/router",
"description": "Universal router for SolidJS",
"author": "Ryan Carniato",
"contributors": [
"Ryan Turnquist"
],
"license": "MIT",
"version": "0.16.1",
"homepage": "https://github.com/solidjs/solid-router#readme",
"repository": {
"type": "git",
"url": "https://github.com/solidjs/solid-router"
},
"publishConfig": {
"access": "public"
},
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"solid": "./dist/index.jsx",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"sideEffects": false,
"devDependencies": {
"@babel/core": "^7.26.0",
"@babel/preset-typescript": "^7.26.0",
"@changesets/cli": "^2.27.10",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-node-resolve": "15.3.0",
"@rollup/plugin-terser": "0.4.4",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.0",
"babel-preset-solid": "^1.9.3",
"jsdom": "^25.0.1",
"prettier": "^3.4.1",
"rollup": "^4.27.4",
"solid-js": "^1.9.3",
"typescript": "^5.7.2",
"vite": "^6.0.0",
"vite-plugin-solid": "^2.11.0",
"vitest": "^2.1.6"
},
"peerDependencies": {
"solid-js": "^1.8.6"
},
"scripts": {
"build": "rm -rf dist && tsc && rollup -c",
"test": "vitest run && npm run test:types",
"test:watch": "vitest",
"test:types": "tsc --project tsconfig.test.json",
"pretty": "prettier --write \"{src,test}/**/*.{ts,tsx}\"",
"release": "pnpm build && changeset publish"
}
}