@kasperrt/smolter 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{src/internal → .generated}/client/index.ts +1 -0
- package/.generated/core/environment.ts +43 -0
- package/{src/internal → .generated}/core/errors.ts +1 -1
- package/{src/internal → .generated}/core/index.ts +1 -0
- package/.generated/core/navigation-router.ts +107 -0
- package/.generated/core/navigation.ts +147 -0
- package/.generated/core/presentation.ts +108 -0
- package/.generated/core/resource-types.ts +44 -0
- package/.generated/core/resources.ts +444 -0
- package/.generated/core/responses.ts +86 -0
- package/{src/internal → .generated}/core/router.ts +136 -63
- package/{src/internal → .generated}/core/serialize.ts +7 -2
- package/.generated/core/store.ts +25 -0
- package/.generated/core/submission.ts +116 -0
- package/{src/internal → .generated}/core/types.ts +18 -1
- package/.generated/core/url.ts +29 -0
- package/.generated/core/utils.ts +5 -0
- package/.generated/preact/await.tsx +41 -0
- package/.generated/preact/client.tsx +93 -0
- package/.generated/preact/context.ts +59 -0
- package/.generated/preact/document.tsx +198 -0
- package/{src/internal → .generated}/preact/fetcher.ts +43 -23
- package/.generated/preact/form.ts +58 -0
- package/{src/internal → .generated}/preact/hooks.ts +25 -28
- package/.generated/preact/index.ts +34 -0
- package/.generated/preact/lazy-route.ts +100 -0
- package/.generated/preact/navigation-state.ts +9 -0
- package/.generated/preact/navigation.tsx +147 -0
- package/.generated/preact/root-context.ts +21 -0
- package/.generated/preact/root-data.ts +45 -0
- package/.generated/preact/route-hooks.tsx +170 -0
- package/.generated/preact/route-types.ts +76 -0
- package/.generated/preact/router.tsx +107 -0
- package/{src/internal → .generated}/preact/routes.ts +17 -9
- package/.generated/react/context.ts +59 -0
- package/.generated/react/data.ts +25 -0
- package/{src/internal → .generated}/react/fetcher.ts +13 -11
- package/.generated/react/form.ts +58 -0
- package/{src/internal → .generated}/react/hooks.ts +9 -14
- package/{src/internal/preact → .generated/react}/index.ts +5 -1
- package/{src/internal → .generated}/react/link.ts +13 -21
- package/.generated/react/resources/components.tsx +404 -0
- package/{src/internal → .generated}/react/routes.ts +17 -9
- package/.generated/server/application.tsx +185 -0
- package/.generated/server/assets.ts +19 -0
- package/.generated/server/handler.ts +69 -0
- package/.generated/server/http.ts +55 -0
- package/{src/internal → .generated}/server/index.ts +3 -3
- package/.generated/server/node.ts +4 -0
- package/.generated/server/preact.ts +7 -0
- package/.generated/vite/application/browser-boundary.ts +42 -0
- package/.generated/vite/application/lazy-files.ts +136 -0
- package/.generated/vite/application/vite.ts +144 -0
- package/{src/preact-vite.ts → .generated/vite/preact.ts} +9 -3
- package/{src/react-vite.ts → .generated/vite/react.ts} +3 -3
- package/CHANGELOG.md +54 -0
- package/README.md +227 -35
- package/dist/client/deserialize.js +10 -0
- package/dist/{internal/client → client}/index.d.ts +1 -0
- package/dist/client/index.js +46 -0
- package/dist/core/environment.d.ts +12 -0
- package/dist/core/environment.js +23 -0
- package/dist/core/errors.js +7 -0
- package/dist/{internal/core → core}/index.d.ts +1 -0
- package/dist/core/match.js +33 -0
- package/dist/core/navigation-router.d.ts +15 -0
- package/dist/core/navigation-router.js +64 -0
- package/dist/core/navigation.d.ts +15 -0
- package/dist/core/navigation.js +92 -0
- package/dist/core/presentation.d.ts +5 -0
- package/dist/core/presentation.js +69 -0
- package/dist/core/resource-types.d.ts +37 -0
- package/dist/core/resources.d.ts +19 -0
- package/dist/core/resources.js +345 -0
- package/dist/core/responses.d.ts +15 -0
- package/dist/core/responses.js +48 -0
- package/dist/{internal/core → core}/router.d.ts +1 -1
- package/dist/core/router.js +204 -0
- package/dist/{internal/core → core}/serialize.d.ts +2 -0
- package/dist/core/serialize.js +17 -0
- package/dist/core/store.d.ts +6 -0
- package/dist/core/store.js +21 -0
- package/dist/core/submission.d.ts +30 -0
- package/dist/core/submission.js +41 -0
- package/dist/{internal/core → core}/types.d.ts +16 -1
- package/dist/core/url.d.ts +7 -0
- package/dist/core/url.js +12 -0
- package/dist/core/utils.d.ts +5 -0
- package/dist/core/utils.js +5 -0
- package/dist/files/index.js +64 -0
- package/dist/preact/await.d.ts +7 -0
- package/dist/preact/await.js +19 -0
- package/dist/preact/client.d.ts +7 -0
- package/dist/preact/client.js +67 -0
- package/dist/preact/context.d.ts +18 -0
- package/dist/preact/context.js +23 -0
- package/dist/preact/document.d.ts +15 -0
- package/dist/preact/document.js +155 -0
- package/dist/{internal/preact → preact}/fetcher.d.ts +9 -5
- package/dist/preact/fetcher.js +45 -0
- package/dist/{internal/preact → preact}/form.d.ts +5 -6
- package/dist/preact/form.js +21 -0
- package/dist/{internal/preact → preact}/hooks.d.ts +7 -6
- package/dist/preact/hooks.js +25 -0
- package/dist/preact/index.d.ts +18 -0
- package/dist/preact/index.js +15 -0
- package/dist/preact/lazy-route.d.ts +19 -0
- package/dist/preact/lazy-route.js +51 -0
- package/dist/preact/navigation-state.d.ts +2 -0
- package/dist/preact/navigation-state.js +9 -0
- package/dist/preact/navigation.d.ts +28 -0
- package/dist/preact/navigation.js +60 -0
- package/dist/preact/root-context.d.ts +13 -0
- package/dist/preact/root-context.js +9 -0
- package/dist/preact/root-data.d.ts +8 -0
- package/dist/preact/root-data.js +28 -0
- package/dist/preact/route-hooks.d.ts +32 -0
- package/dist/preact/route-hooks.js +94 -0
- package/dist/preact/route-types.d.ts +54 -0
- package/dist/preact/router.d.ts +16 -0
- package/dist/preact/router.js +63 -0
- package/dist/{internal/preact → preact}/routes.d.ts +1 -1
- package/dist/preact/routes.js +12 -0
- package/dist/{internal/preact → preact}/runtime.js +1 -1
- package/dist/react/context.d.ts +18 -0
- package/dist/react/context.js +23 -0
- package/dist/react/data.d.ts +5 -0
- package/dist/react/data.js +3 -0
- package/dist/{internal/react → react}/fetcher.d.ts +2 -2
- package/dist/react/fetcher.js +34 -0
- package/dist/{internal/react → react}/form.d.ts +5 -6
- package/dist/react/form.js +21 -0
- package/dist/react/hooks.js +25 -0
- package/dist/{internal/react → react}/index.d.ts +1 -1
- package/dist/react/index.js +10 -0
- package/dist/{internal/react → react}/link.d.ts +2 -2
- package/dist/react/link.js +27 -0
- package/dist/react/resources/components.d.ts +64 -0
- package/dist/react/resources/components.js +239 -0
- package/dist/{internal/react → react}/routes.d.ts +1 -1
- package/dist/react/routes.js +12 -0
- package/dist/react/runtime.js +1 -0
- package/dist/server/application.d.ts +4 -0
- package/dist/server/application.js +119 -0
- package/dist/server/assets.d.ts +5 -0
- package/dist/server/assets.js +7 -0
- package/dist/server/handler.d.ts +19 -0
- package/dist/server/handler.js +22 -0
- package/dist/server/http.d.ts +4 -0
- package/dist/server/http.js +27 -0
- package/dist/server/index.js +76 -0
- package/dist/server/node.d.ts +3 -0
- package/dist/server/node.js +3 -0
- package/dist/server/preact.d.ts +3 -0
- package/dist/server/preact.js +4 -0
- package/dist/vite/application/browser-boundary.d.ts +3 -0
- package/dist/vite/application/browser-boundary.js +35 -0
- package/dist/vite/application/lazy-files.d.ts +2 -0
- package/dist/vite/application/lazy-files.js +87 -0
- package/dist/vite/application/vite.d.ts +9 -0
- package/dist/vite/application/vite.js +101 -0
- package/dist/vite/index.js +104 -0
- package/dist/{preact-vite.d.ts → vite/preact.d.ts} +5 -3
- package/dist/vite/preact.js +15 -0
- package/dist/{react-vite.d.ts → vite/react.d.ts} +3 -3
- package/dist/vite/react.js +14 -0
- package/dist/vite/transport.js +35 -0
- package/jsr.json +28 -16
- package/package.json +116 -36
- package/dist/client.d.ts +0 -2
- package/dist/client.js +0 -2
- package/dist/core.d.ts +0 -2
- package/dist/core.js +0 -2
- package/dist/files.d.ts +0 -2
- package/dist/files.js +0 -2
- package/dist/internal/client/deserialize.js +0 -11
- package/dist/internal/client/index.js +0 -44
- package/dist/internal/core/errors.js +0 -6
- package/dist/internal/core/index.js +0 -7
- package/dist/internal/core/match.js +0 -27
- package/dist/internal/core/router.js +0 -189
- package/dist/internal/core/serialize.js +0 -13
- package/dist/internal/core/types.js +0 -5
- package/dist/internal/core/url.d.ts +0 -2
- package/dist/internal/core/url.js +0 -6
- package/dist/internal/files/index.js +0 -77
- package/dist/internal/preact/context.d.ts +0 -18
- package/dist/internal/preact/context.js +0 -20
- package/dist/internal/preact/fetcher.js +0 -28
- package/dist/internal/preact/form.js +0 -41
- package/dist/internal/preact/hooks.js +0 -35
- package/dist/internal/preact/index.d.ts +0 -9
- package/dist/internal/preact/index.js +0 -7
- package/dist/internal/preact/link.d.ts +0 -12
- package/dist/internal/preact/link.js +0 -28
- package/dist/internal/preact/routes.js +0 -22
- package/dist/internal/react/context.d.ts +0 -18
- package/dist/internal/react/context.js +0 -20
- package/dist/internal/react/fetcher.js +0 -28
- package/dist/internal/react/form.js +0 -41
- package/dist/internal/react/hooks.js +0 -35
- package/dist/internal/react/index.js +0 -7
- package/dist/internal/react/link.js +0 -28
- package/dist/internal/react/routes.js +0 -22
- package/dist/internal/react/runtime.js +0 -2
- package/dist/internal/server/index.js +0 -69
- package/dist/internal/vite/index.js +0 -132
- package/dist/internal/vite/transport.js +0 -42
- package/dist/preact-client.d.ts +0 -2
- package/dist/preact-client.js +0 -2
- package/dist/preact-server.d.ts +0 -2
- package/dist/preact-server.js +0 -2
- package/dist/preact-vite.js +0 -9
- package/dist/preact.d.ts +0 -2
- package/dist/preact.js +0 -2
- package/dist/react-client.d.ts +0 -2
- package/dist/react-client.js +0 -2
- package/dist/react-server.d.ts +0 -2
- package/dist/react-server.js +0 -2
- package/dist/react-vite.js +0 -9
- package/dist/react.d.ts +0 -2
- package/dist/react.js +0 -2
- package/dist/server.d.ts +0 -2
- package/dist/server.js +0 -2
- package/dist/utils.d.ts +0 -5
- package/dist/utils.js +0 -5
- package/dist/vite.d.ts +0 -2
- package/dist/vite.js +0 -2
- package/src/client.ts +0 -2
- package/src/core.ts +0 -2
- package/src/files.ts +0 -2
- package/src/internal/core/url.ts +0 -6
- package/src/internal/preact/context.ts +0 -46
- package/src/internal/preact/form.ts +0 -79
- package/src/internal/preact/link.ts +0 -46
- package/src/internal/react/context.ts +0 -46
- package/src/internal/react/form.ts +0 -79
- package/src/internal/react/index.ts +0 -13
- package/src/preact-client.ts +0 -2
- package/src/preact-server.ts +0 -2
- package/src/preact.ts +0 -2
- package/src/react-client.ts +0 -2
- package/src/react-server.ts +0 -2
- package/src/react.ts +0 -2
- package/src/server.ts +0 -2
- package/src/utils.ts +0 -5
- package/src/vite.ts +0 -2
- /package/{src/internal → .generated}/client/deserialize.ts +0 -0
- /package/{src/internal → .generated}/core/match.ts +0 -0
- /package/{src/internal → .generated}/files/index.ts +0 -0
- /package/{src/internal → .generated}/preact/runtime.ts +0 -0
- /package/{src/internal → .generated}/react/runtime.ts +0 -0
- /package/{src/internal → .generated}/vite/index.ts +0 -0
- /package/{src/internal → .generated}/vite/transport.ts +0 -0
- /package/dist/{internal/client → client}/deserialize.d.ts +0 -0
- /package/dist/{internal/core → core}/errors.d.ts +0 -0
- /package/dist/{internal/core → core}/match.d.ts +0 -0
- /package/dist/{internal/files → files}/index.d.ts +0 -0
- /package/dist/{internal/preact → preact}/runtime.d.ts +0 -0
- /package/dist/{internal/react → react}/hooks.d.ts +0 -0
- /package/dist/{internal/react → react}/runtime.d.ts +0 -0
- /package/dist/{internal/server → server}/index.d.ts +0 -0
- /package/dist/{internal/vite → vite}/index.d.ts +0 -0
- /package/dist/{internal/vite → vite}/transport.d.ts +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Router } from "./types.ts";
|
|
2
|
+
export type NavigationType = "POP" | "PUSH" | "REPLACE";
|
|
3
|
+
export interface NavigationSnapshot {
|
|
4
|
+
type: NavigationType;
|
|
5
|
+
state: unknown;
|
|
6
|
+
key: string;
|
|
7
|
+
preventScrollReset: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function scrollPositions(router: Router): Map<string, [number, number]>;
|
|
10
|
+
export declare function navigationStore(router: Router): {
|
|
11
|
+
getSnapshot: () => NavigationSnapshot;
|
|
12
|
+
subscribe(listener: () => void): () => void;
|
|
13
|
+
update(next: NavigationSnapshot): void;
|
|
14
|
+
};
|
|
15
|
+
export declare function connectNavigation(router: Router): void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { navigationClick } from "./url.js";
|
|
2
|
+
import { handoffDocument, leaveDocument, resolveApplicationURL } from "./environment.js";
|
|
3
|
+
import { createStore } from "./store.js";
|
|
4
|
+
//#region .generated/core/navigation.ts
|
|
5
|
+
var scrollHistory = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
function scrollPositions(router) {
|
|
7
|
+
let positions = scrollHistory.get(router);
|
|
8
|
+
if (!positions) {
|
|
9
|
+
positions = /* @__PURE__ */ new Map();
|
|
10
|
+
scrollHistory.set(router, positions);
|
|
11
|
+
}
|
|
12
|
+
return positions;
|
|
13
|
+
}
|
|
14
|
+
var stores = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
function createNavigationStore() {
|
|
16
|
+
return createStore({
|
|
17
|
+
type: "POP",
|
|
18
|
+
state: typeof history === "undefined" ? null : history.state?.state,
|
|
19
|
+
key: typeof history === "undefined" ? "initial" : history.state?.key ?? "initial",
|
|
20
|
+
preventScrollReset: false
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function navigationStore(router) {
|
|
24
|
+
let store = stores.get(router);
|
|
25
|
+
if (!store) {
|
|
26
|
+
store = createNavigationStore();
|
|
27
|
+
stores.set(router, store);
|
|
28
|
+
}
|
|
29
|
+
return store;
|
|
30
|
+
}
|
|
31
|
+
function connectNavigation(router) {
|
|
32
|
+
const store = navigationStore(router);
|
|
33
|
+
const navigate = router.navigate;
|
|
34
|
+
let sequence = 0;
|
|
35
|
+
let pending;
|
|
36
|
+
const committed = () => {
|
|
37
|
+
if (!pending || router.getSnapshot().state !== "idle") return;
|
|
38
|
+
const next = pending;
|
|
39
|
+
pending = void 0;
|
|
40
|
+
if (next.type !== "POP") history.replaceState(next, "", location.href);
|
|
41
|
+
store.update(next);
|
|
42
|
+
};
|
|
43
|
+
const unsubscribe = router.subscribe(committed);
|
|
44
|
+
const rememberScroll = () => {
|
|
45
|
+
scrollPositions(router).set(store.getSnapshot().key, [window.scrollX, window.scrollY]);
|
|
46
|
+
};
|
|
47
|
+
router.navigate = async (href, options = {}) => {
|
|
48
|
+
const destination = resolveApplicationURL(new URL(href, router.getSnapshot().url));
|
|
49
|
+
if (destination.origin !== location.origin) {
|
|
50
|
+
leaveDocument(destination);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
rememberScroll();
|
|
54
|
+
const current = ++sequence;
|
|
55
|
+
pending = {
|
|
56
|
+
type: options.replace ? "REPLACE" : "PUSH",
|
|
57
|
+
state: options.state ?? null,
|
|
58
|
+
key: `${Date.now().toString(36)}-${current}`,
|
|
59
|
+
preventScrollReset: options.preventScrollReset ?? false
|
|
60
|
+
};
|
|
61
|
+
await navigate(href, options);
|
|
62
|
+
committed();
|
|
63
|
+
};
|
|
64
|
+
const pop = () => {
|
|
65
|
+
rememberScroll();
|
|
66
|
+
pending = {
|
|
67
|
+
...history.state,
|
|
68
|
+
type: "POP",
|
|
69
|
+
key: history.state?.key ?? "initial",
|
|
70
|
+
preventScrollReset: false
|
|
71
|
+
};
|
|
72
|
+
committed();
|
|
73
|
+
};
|
|
74
|
+
const handoff = (event) => {
|
|
75
|
+
const anchor = event.target instanceof Element ? event.target.closest("a[href]") : null;
|
|
76
|
+
if (!(anchor instanceof HTMLAnchorElement) || !navigationClick(event, anchor)) return;
|
|
77
|
+
const target = resolveApplicationURL(new URL(anchor.href));
|
|
78
|
+
handoffDocument(event, target);
|
|
79
|
+
};
|
|
80
|
+
if (typeof document !== "undefined") document.addEventListener("click", handoff);
|
|
81
|
+
window.addEventListener("popstate", pop);
|
|
82
|
+
const dispose = router.dispose;
|
|
83
|
+
router.dispose = () => {
|
|
84
|
+
pending = void 0;
|
|
85
|
+
unsubscribe();
|
|
86
|
+
window.removeEventListener("popstate", pop);
|
|
87
|
+
if (typeof document !== "undefined") document.removeEventListener("click", handoff);
|
|
88
|
+
dispose();
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { connectNavigation, navigationStore, scrollPositions };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//#region .generated/core/presentation.ts
|
|
2
|
+
var pending = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function pendingLocation(router) {
|
|
4
|
+
const snapshot = pending.get(router)?.();
|
|
5
|
+
return snapshot?.state !== "idle" && snapshot?.url ? new URL(snapshot.url) : void 0;
|
|
6
|
+
}
|
|
7
|
+
function retainRoute(router, commitView) {
|
|
8
|
+
const read = router.getSnapshot;
|
|
9
|
+
pending.set(router, read);
|
|
10
|
+
let viewTransition;
|
|
11
|
+
const navigate = router.navigate;
|
|
12
|
+
router.navigate = (href, options = {}) => {
|
|
13
|
+
viewTransition = options.viewTransition;
|
|
14
|
+
return navigate(href, options);
|
|
15
|
+
};
|
|
16
|
+
let visible = read();
|
|
17
|
+
let revision = 0;
|
|
18
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
19
|
+
const publish = () => {
|
|
20
|
+
for (const listener of listeners) listener();
|
|
21
|
+
};
|
|
22
|
+
const unsubscribe = router.subscribe(() => {
|
|
23
|
+
const next = read();
|
|
24
|
+
const current = ++revision;
|
|
25
|
+
if (next.state !== "idle" && visible.loaded) {
|
|
26
|
+
visible = {
|
|
27
|
+
...visible,
|
|
28
|
+
state: next.state
|
|
29
|
+
};
|
|
30
|
+
publish();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const commit = () => {
|
|
34
|
+
if (current !== revision) return;
|
|
35
|
+
commitView(() => {
|
|
36
|
+
visible = next;
|
|
37
|
+
publish();
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
const previousURL = new URL(visible.url);
|
|
41
|
+
const nextURL = new URL(next.url);
|
|
42
|
+
const changed = previousURL.pathname + previousURL.search !== nextURL.pathname + nextURL.search;
|
|
43
|
+
const component = (path) => {
|
|
44
|
+
const route = router.routes.find((item) => item.path === path);
|
|
45
|
+
return route?.resolveComponent?.() ?? route?.default;
|
|
46
|
+
};
|
|
47
|
+
const previousComponent = component(visible.path);
|
|
48
|
+
const sharedView = previousComponent && previousComponent === component(next.path);
|
|
49
|
+
if (changed && visible.loaded && viewTransition !== false && !sharedView && previousURL.pathname !== nextURL.pathname && typeof document !== "undefined" && typeof document.startViewTransition === "function" && !matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
50
|
+
document.startViewTransition(commit).ready.catch(() => {});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
commit();
|
|
54
|
+
});
|
|
55
|
+
router.getSnapshot = () => visible;
|
|
56
|
+
router.subscribe = (listener) => {
|
|
57
|
+
listeners.add(listener);
|
|
58
|
+
return () => listeners.delete(listener);
|
|
59
|
+
};
|
|
60
|
+
const dispose = router.dispose;
|
|
61
|
+
router.dispose = () => {
|
|
62
|
+
unsubscribe();
|
|
63
|
+
pending.delete(router);
|
|
64
|
+
listeners.clear();
|
|
65
|
+
dispose();
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { pendingLocation, retainRoute };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type Params = Readonly<Record<string, string>>;
|
|
2
|
+
export interface LoaderFunctionArgs {
|
|
3
|
+
params: Params;
|
|
4
|
+
signal: AbortSignal;
|
|
5
|
+
}
|
|
6
|
+
export interface ActionFunctionArgs<Input = unknown> {
|
|
7
|
+
input: Input;
|
|
8
|
+
params: Params;
|
|
9
|
+
signal: AbortSignal;
|
|
10
|
+
}
|
|
11
|
+
export interface DataResult<Data> {
|
|
12
|
+
data: Data | null;
|
|
13
|
+
error: string;
|
|
14
|
+
unexpected?: true;
|
|
15
|
+
}
|
|
16
|
+
export interface ResourceModule {
|
|
17
|
+
action?: (args: ActionFunctionArgs) => Promise<DataResult<unknown>>;
|
|
18
|
+
loader?: (args: LoaderFunctionArgs) => Promise<DataResult<unknown>>;
|
|
19
|
+
shouldRevalidate?: (args: ShouldRevalidateFunctionArgs) => boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface ShouldRevalidateFunctionArgs {
|
|
22
|
+
actionResult: DataResult<unknown>;
|
|
23
|
+
defaultShouldRevalidate: boolean;
|
|
24
|
+
params: Params;
|
|
25
|
+
}
|
|
26
|
+
export type NavigationState = "idle" | "loading" | "submitting";
|
|
27
|
+
export interface RouteState {
|
|
28
|
+
actionData: unknown;
|
|
29
|
+
actionError: string;
|
|
30
|
+
actionState: "idle" | "submitting";
|
|
31
|
+
loaderData: unknown;
|
|
32
|
+
loaderError: string;
|
|
33
|
+
loaderInitialized: boolean;
|
|
34
|
+
loaderState: "idle" | "loading";
|
|
35
|
+
navigationState: NavigationState;
|
|
36
|
+
unexpectedError: boolean;
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DataResult, Params, ResourceModule, RouteState } from "./resource-types.ts";
|
|
2
|
+
export declare class ResourceRouter {
|
|
3
|
+
#private;
|
|
4
|
+
constructor(routes: ReadonlyMap<string, ResourceModule>);
|
|
5
|
+
dispose(): void;
|
|
6
|
+
getRoute(routeId: string): ResourceModule | null;
|
|
7
|
+
getSnapshot(routeId: string, params: Params): RouteState;
|
|
8
|
+
hydrateRoute<Data>(routeId: string, data: Data, params?: Params): void;
|
|
9
|
+
persist(routeId: string, params?: Params): void;
|
|
10
|
+
disposeRoute(routeId: string, params?: Params): void;
|
|
11
|
+
load<Data>(routeId: string, params?: Params, force?: boolean): Promise<DataResult<Data>>;
|
|
12
|
+
subscribe(routeId: string, params: Params, listener: () => void): () => void;
|
|
13
|
+
submit<Data>(routeId: string, input: unknown, params?: Params): Promise<DataResult<Data>>;
|
|
14
|
+
fetchLoader<Data>(routeId: string, params: Params, signal: AbortSignal): Promise<DataResult<Data>>;
|
|
15
|
+
fetchAction<Data>(routeId: string, input: unknown, params: Params, signal: AbortSignal): Promise<DataResult<Data>>;
|
|
16
|
+
retry(routeId: string, params: Params): Promise<DataResult<unknown>>;
|
|
17
|
+
reportUnexpected(routeId: string, params: Params): void;
|
|
18
|
+
}
|
|
19
|
+
export declare function createResourceRouter(routes: ReadonlyMap<string, ResourceModule>): ResourceRouter;
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { safeWrapAsync } from "./errors.js";
|
|
2
|
+
//#region .generated/core/resources.ts
|
|
3
|
+
var IDLE_ROUTE_STATE = {
|
|
4
|
+
actionData: null,
|
|
5
|
+
actionError: "",
|
|
6
|
+
actionState: "idle",
|
|
7
|
+
loaderData: null,
|
|
8
|
+
loaderError: "",
|
|
9
|
+
loaderInitialized: false,
|
|
10
|
+
loaderState: "idle",
|
|
11
|
+
navigationState: "idle",
|
|
12
|
+
unexpectedError: false
|
|
13
|
+
};
|
|
14
|
+
var ResourceRouter = class {
|
|
15
|
+
#cleanupTimers = /* @__PURE__ */ new Map();
|
|
16
|
+
#controllers = /* @__PURE__ */ new Map();
|
|
17
|
+
#inFlightLoads = /* @__PURE__ */ new Map();
|
|
18
|
+
#listeners = /* @__PURE__ */ new Map();
|
|
19
|
+
#persistentRoutes = /* @__PURE__ */ new Set();
|
|
20
|
+
#routes;
|
|
21
|
+
#states = /* @__PURE__ */ new Map();
|
|
22
|
+
constructor(routes) {
|
|
23
|
+
this.#routes = routes;
|
|
24
|
+
}
|
|
25
|
+
dispose() {
|
|
26
|
+
for (const controller of this.#controllers.values()) controller.abort();
|
|
27
|
+
this.#controllers.clear();
|
|
28
|
+
for (const timer of this.#cleanupTimers.values()) clearTimeout(timer);
|
|
29
|
+
this.#cleanupTimers.clear();
|
|
30
|
+
this.#inFlightLoads.clear();
|
|
31
|
+
this.#listeners.clear();
|
|
32
|
+
this.#persistentRoutes.clear();
|
|
33
|
+
}
|
|
34
|
+
getRoute(routeId) {
|
|
35
|
+
return this.#routes.get(routeId) ?? null;
|
|
36
|
+
}
|
|
37
|
+
getSnapshot(routeId, params) {
|
|
38
|
+
return this.#states.get(createRouteKey(routeId, params)) ?? IDLE_ROUTE_STATE;
|
|
39
|
+
}
|
|
40
|
+
hydrateRoute(routeId, data, params = {}) {
|
|
41
|
+
const routeKey = createRouteKey(routeId, params);
|
|
42
|
+
const currentState = this.#states.get(routeKey) ?? IDLE_ROUTE_STATE;
|
|
43
|
+
this.#setState(routeKey, {
|
|
44
|
+
...currentState,
|
|
45
|
+
loaderData: data,
|
|
46
|
+
loaderError: "",
|
|
47
|
+
loaderInitialized: true,
|
|
48
|
+
loaderState: "idle",
|
|
49
|
+
navigationState: currentState.actionState === "submitting" ? "submitting" : "idle",
|
|
50
|
+
unexpectedError: false
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
persist(routeId, params = {}) {
|
|
54
|
+
const routeKey = createRouteKey(routeId, params);
|
|
55
|
+
this.#persistentRoutes.add(routeKey);
|
|
56
|
+
const cleanupTimer = this.#cleanupTimers.get(routeKey);
|
|
57
|
+
if (!cleanupTimer) return;
|
|
58
|
+
clearTimeout(cleanupTimer);
|
|
59
|
+
this.#cleanupTimers.delete(routeKey);
|
|
60
|
+
}
|
|
61
|
+
disposeRoute(routeId, params = {}) {
|
|
62
|
+
this.#disposeRouteKey(createRouteKey(routeId, params));
|
|
63
|
+
}
|
|
64
|
+
#disposeRouteKey(routeKey) {
|
|
65
|
+
this.#persistentRoutes.delete(routeKey);
|
|
66
|
+
const cleanupTimer = this.#cleanupTimers.get(routeKey);
|
|
67
|
+
if (cleanupTimer) clearTimeout(cleanupTimer);
|
|
68
|
+
this.#cleanupTimers.delete(routeKey);
|
|
69
|
+
this.#controllers.get(routeKey)?.abort();
|
|
70
|
+
this.#controllers.get(`${routeKey}:action`)?.abort();
|
|
71
|
+
this.#controllers.delete(routeKey);
|
|
72
|
+
this.#controllers.delete(`${routeKey}:action`);
|
|
73
|
+
this.#inFlightLoads.delete(routeKey);
|
|
74
|
+
this.#states.delete(routeKey);
|
|
75
|
+
this.#notify(routeKey);
|
|
76
|
+
}
|
|
77
|
+
load(routeId, params = {}, force = false) {
|
|
78
|
+
const routeKey = createRouteKey(routeId, params);
|
|
79
|
+
const route = this.#routes.get(routeId);
|
|
80
|
+
if (!route?.loader) return Promise.resolve({
|
|
81
|
+
data: null,
|
|
82
|
+
error: "Route loader not found."
|
|
83
|
+
});
|
|
84
|
+
const currentState = this.#states.get(routeKey);
|
|
85
|
+
if (!force && currentState?.loaderInitialized) return Promise.resolve({
|
|
86
|
+
data: currentState?.loaderData,
|
|
87
|
+
error: currentState?.loaderError ?? ""
|
|
88
|
+
});
|
|
89
|
+
const currentLoad = this.#inFlightLoads.get(routeKey);
|
|
90
|
+
if (force && currentLoad) {
|
|
91
|
+
this.#controllers.get(routeKey)?.abort();
|
|
92
|
+
this.#inFlightLoads.delete(routeKey);
|
|
93
|
+
}
|
|
94
|
+
if (!force && currentLoad) return currentLoad;
|
|
95
|
+
const controller = this.#replaceController(routeKey);
|
|
96
|
+
this.#setState(routeKey, {
|
|
97
|
+
...currentState ?? IDLE_ROUTE_STATE,
|
|
98
|
+
loaderError: "",
|
|
99
|
+
loaderState: "loading",
|
|
100
|
+
navigationState: currentState?.actionState === "submitting" ? "submitting" : "loading",
|
|
101
|
+
unexpectedError: false
|
|
102
|
+
});
|
|
103
|
+
const load = this.#runLoader(route, routeKey, params, controller);
|
|
104
|
+
this.#inFlightLoads.set(routeKey, load);
|
|
105
|
+
return load;
|
|
106
|
+
}
|
|
107
|
+
subscribe(routeId, params, listener) {
|
|
108
|
+
const routeKey = createRouteKey(routeId, params);
|
|
109
|
+
const cleanupTimer = this.#cleanupTimers.get(routeKey);
|
|
110
|
+
if (cleanupTimer) {
|
|
111
|
+
clearTimeout(cleanupTimer);
|
|
112
|
+
this.#cleanupTimers.delete(routeKey);
|
|
113
|
+
}
|
|
114
|
+
const listeners = this.#listeners.get(routeKey) ?? /* @__PURE__ */ new Set();
|
|
115
|
+
listeners.add(listener);
|
|
116
|
+
this.#listeners.set(routeKey, listeners);
|
|
117
|
+
return () => {
|
|
118
|
+
if (!listeners.delete(listener) || listeners.size > 0) return;
|
|
119
|
+
this.#listeners.delete(routeKey);
|
|
120
|
+
if (this.#persistentRoutes.has(routeKey)) return;
|
|
121
|
+
const timer = setTimeout(() => this.#disposeRouteKey(routeKey), routeCleanupGraceMs);
|
|
122
|
+
this.#cleanupTimers.set(routeKey, timer);
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
async submit(routeId, input, params = {}) {
|
|
126
|
+
const routeKey = createRouteKey(routeId, params);
|
|
127
|
+
const route = this.#routes.get(routeId);
|
|
128
|
+
if (!route?.action) return {
|
|
129
|
+
data: null,
|
|
130
|
+
error: "Route action not found."
|
|
131
|
+
};
|
|
132
|
+
const controllerKey = `${routeKey}:action`;
|
|
133
|
+
const controller = this.#replaceController(controllerKey);
|
|
134
|
+
const currentState = this.#states.get(routeKey) ?? IDLE_ROUTE_STATE;
|
|
135
|
+
this.#setState(routeKey, {
|
|
136
|
+
...currentState,
|
|
137
|
+
actionError: "",
|
|
138
|
+
actionState: "submitting",
|
|
139
|
+
navigationState: "submitting",
|
|
140
|
+
unexpectedError: false
|
|
141
|
+
});
|
|
142
|
+
const { error, data: result } = await safeWrapAsync(() => route.action?.({
|
|
143
|
+
input,
|
|
144
|
+
params,
|
|
145
|
+
signal: controller.signal
|
|
146
|
+
}));
|
|
147
|
+
if (this.#controllers.get(controllerKey) === controller) this.#controllers.delete(controllerKey);
|
|
148
|
+
if (controller.signal.aborted) return {
|
|
149
|
+
data: null,
|
|
150
|
+
error: ""
|
|
151
|
+
};
|
|
152
|
+
const latestState = this.#states.get(routeKey) ?? IDLE_ROUTE_STATE;
|
|
153
|
+
if (error || !result) {
|
|
154
|
+
const publicError = "The request could not be completed.";
|
|
155
|
+
this.#setState(routeKey, {
|
|
156
|
+
...latestState,
|
|
157
|
+
actionData: null,
|
|
158
|
+
actionError: publicError,
|
|
159
|
+
actionState: "idle",
|
|
160
|
+
navigationState: latestState.loaderState === "loading" ? "loading" : "idle",
|
|
161
|
+
unexpectedError: true
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
data: null,
|
|
165
|
+
error: publicError,
|
|
166
|
+
unexpected: true
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
this.#setState(routeKey, {
|
|
170
|
+
...latestState,
|
|
171
|
+
actionData: result.data,
|
|
172
|
+
actionError: result.error,
|
|
173
|
+
actionState: "idle",
|
|
174
|
+
navigationState: latestState.loaderState === "loading" ? "loading" : "idle",
|
|
175
|
+
unexpectedError: false
|
|
176
|
+
});
|
|
177
|
+
const actionResult = {
|
|
178
|
+
data: result.data,
|
|
179
|
+
error: result.error
|
|
180
|
+
};
|
|
181
|
+
const { error: revalidationError, data: shouldRevalidate } = await safeWrapAsync(() => route.shouldRevalidate?.({
|
|
182
|
+
actionResult: result,
|
|
183
|
+
defaultShouldRevalidate: Boolean(route.loader),
|
|
184
|
+
params
|
|
185
|
+
}) ?? Boolean(route.loader));
|
|
186
|
+
if (revalidationError) {
|
|
187
|
+
const publicError = "The request could not be completed.";
|
|
188
|
+
this.#setState(routeKey, {
|
|
189
|
+
...this.#states.get(routeKey) ?? IDLE_ROUTE_STATE,
|
|
190
|
+
actionError: publicError,
|
|
191
|
+
actionState: "idle",
|
|
192
|
+
unexpectedError: true
|
|
193
|
+
});
|
|
194
|
+
return {
|
|
195
|
+
data: null,
|
|
196
|
+
error: publicError,
|
|
197
|
+
unexpected: true
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (shouldRevalidate) await this.load(routeId, params, true);
|
|
201
|
+
return actionResult;
|
|
202
|
+
}
|
|
203
|
+
async fetchLoader(routeId, params, signal) {
|
|
204
|
+
const route = this.#routes.get(routeId);
|
|
205
|
+
if (!route?.loader) return {
|
|
206
|
+
data: null,
|
|
207
|
+
error: "Route loader not found."
|
|
208
|
+
};
|
|
209
|
+
const { error, data: result } = await safeWrapAsync(() => route.loader?.({
|
|
210
|
+
params,
|
|
211
|
+
signal
|
|
212
|
+
}));
|
|
213
|
+
if (signal.aborted) return {
|
|
214
|
+
data: null,
|
|
215
|
+
error: ""
|
|
216
|
+
};
|
|
217
|
+
if (error || !result) return {
|
|
218
|
+
data: null,
|
|
219
|
+
error: "The route could not be loaded.",
|
|
220
|
+
unexpected: true
|
|
221
|
+
};
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
async fetchAction(routeId, input, params, signal) {
|
|
225
|
+
const route = this.#routes.get(routeId);
|
|
226
|
+
if (!route?.action) return {
|
|
227
|
+
data: null,
|
|
228
|
+
error: "Route action not found."
|
|
229
|
+
};
|
|
230
|
+
const { error, data: result } = await safeWrapAsync(() => route.action?.({
|
|
231
|
+
input,
|
|
232
|
+
params,
|
|
233
|
+
signal
|
|
234
|
+
}));
|
|
235
|
+
if (signal.aborted) return {
|
|
236
|
+
data: null,
|
|
237
|
+
error: ""
|
|
238
|
+
};
|
|
239
|
+
if (error || !result) return {
|
|
240
|
+
data: null,
|
|
241
|
+
error: "The request could not be completed.",
|
|
242
|
+
unexpected: true
|
|
243
|
+
};
|
|
244
|
+
const { error: revalidationError, data: shouldRevalidate } = await safeWrapAsync(() => route.shouldRevalidate?.({
|
|
245
|
+
actionResult: result,
|
|
246
|
+
defaultShouldRevalidate: Boolean(route.loader),
|
|
247
|
+
params
|
|
248
|
+
}) ?? Boolean(route.loader));
|
|
249
|
+
if (signal.aborted) return {
|
|
250
|
+
data: null,
|
|
251
|
+
error: ""
|
|
252
|
+
};
|
|
253
|
+
if (revalidationError) return {
|
|
254
|
+
data: null,
|
|
255
|
+
error: "The request could not be completed.",
|
|
256
|
+
unexpected: true
|
|
257
|
+
};
|
|
258
|
+
if (shouldRevalidate) await this.load(routeId, params, true);
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
retry(routeId, params) {
|
|
262
|
+
const routeKey = createRouteKey(routeId, params);
|
|
263
|
+
this.#states.set(routeKey, IDLE_ROUTE_STATE);
|
|
264
|
+
this.#notify(routeKey);
|
|
265
|
+
return this.load(routeId, params, true);
|
|
266
|
+
}
|
|
267
|
+
reportUnexpected(routeId, params) {
|
|
268
|
+
const routeKey = createRouteKey(routeId, params);
|
|
269
|
+
const currentState = this.#states.get(routeKey) ?? IDLE_ROUTE_STATE;
|
|
270
|
+
this.#setState(routeKey, {
|
|
271
|
+
...currentState,
|
|
272
|
+
unexpectedError: true
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
async #runLoader(route, routeKey, params, controller) {
|
|
276
|
+
const { error, data: result } = await safeWrapAsync(() => route.loader?.({
|
|
277
|
+
params,
|
|
278
|
+
signal: controller.signal
|
|
279
|
+
}) ?? Promise.resolve({
|
|
280
|
+
data: null,
|
|
281
|
+
error: ""
|
|
282
|
+
}));
|
|
283
|
+
if (this.#controllers.get(routeKey) === controller) {
|
|
284
|
+
this.#controllers.delete(routeKey);
|
|
285
|
+
this.#inFlightLoads.delete(routeKey);
|
|
286
|
+
}
|
|
287
|
+
if (controller.signal.aborted) return {
|
|
288
|
+
data: null,
|
|
289
|
+
error: ""
|
|
290
|
+
};
|
|
291
|
+
if (error || !result) {
|
|
292
|
+
const publicError = "The route could not be loaded.";
|
|
293
|
+
this.#setState(routeKey, {
|
|
294
|
+
actionData: null,
|
|
295
|
+
actionError: "",
|
|
296
|
+
actionState: "idle",
|
|
297
|
+
loaderData: null,
|
|
298
|
+
loaderError: publicError,
|
|
299
|
+
loaderInitialized: true,
|
|
300
|
+
loaderState: "idle",
|
|
301
|
+
navigationState: "idle",
|
|
302
|
+
unexpectedError: true
|
|
303
|
+
});
|
|
304
|
+
return {
|
|
305
|
+
data: null,
|
|
306
|
+
error: publicError,
|
|
307
|
+
unexpected: true
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const currentState = this.#states.get(routeKey) ?? IDLE_ROUTE_STATE;
|
|
311
|
+
this.#setState(routeKey, {
|
|
312
|
+
...currentState,
|
|
313
|
+
loaderData: result.data,
|
|
314
|
+
loaderError: result.error,
|
|
315
|
+
loaderInitialized: true,
|
|
316
|
+
loaderState: "idle",
|
|
317
|
+
navigationState: currentState.actionState === "submitting" ? "submitting" : "idle",
|
|
318
|
+
unexpectedError: false
|
|
319
|
+
});
|
|
320
|
+
return result;
|
|
321
|
+
}
|
|
322
|
+
#replaceController(key) {
|
|
323
|
+
this.#controllers.get(key)?.abort();
|
|
324
|
+
const controller = new AbortController();
|
|
325
|
+
this.#controllers.set(key, controller);
|
|
326
|
+
return controller;
|
|
327
|
+
}
|
|
328
|
+
#setState(routeKey, state) {
|
|
329
|
+
this.#states.set(routeKey, state);
|
|
330
|
+
this.#notify(routeKey);
|
|
331
|
+
}
|
|
332
|
+
#notify(routeKey) {
|
|
333
|
+
for (const listener of this.#listeners.get(routeKey) ?? []) listener();
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
function createResourceRouter(routes) {
|
|
337
|
+
return new ResourceRouter(routes);
|
|
338
|
+
}
|
|
339
|
+
function createRouteKey(routeId, params) {
|
|
340
|
+
const normalizedParams = Object.entries(params).sort(([left], [right]) => left.localeCompare(right));
|
|
341
|
+
return `${routeId}:${JSON.stringify(normalizedParams)}`;
|
|
342
|
+
}
|
|
343
|
+
var routeCleanupGraceMs = 100;
|
|
344
|
+
//#endregion
|
|
345
|
+
export { ResourceRouter, createResourceRouter };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RouteError extends Error {
|
|
2
|
+
status: number;
|
|
3
|
+
statusText: string;
|
|
4
|
+
data?: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface DataResponse<T> {
|
|
7
|
+
value: T;
|
|
8
|
+
init: ResponseInit;
|
|
9
|
+
__routeData: true;
|
|
10
|
+
}
|
|
11
|
+
export declare function data<T>(value: T, init?: ResponseInit): DataResponse<T>;
|
|
12
|
+
export declare function redirect(location: string, init?: number | ResponseInit): Response;
|
|
13
|
+
export declare function isRouteErrorResponse(value: unknown): value is RouteError;
|
|
14
|
+
export declare function normalizeResult(value: unknown): Promise<unknown>;
|
|
15
|
+
export declare function resolveData(value: unknown): Promise<unknown>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//#region .generated/core/responses.ts
|
|
2
|
+
function data(value, init = {}) {
|
|
3
|
+
return {
|
|
4
|
+
value,
|
|
5
|
+
init,
|
|
6
|
+
__routeData: true
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function redirect(location, init = 302) {
|
|
10
|
+
const options = typeof init === "number" ? { status: init } : init;
|
|
11
|
+
const headers = new Headers(options.headers);
|
|
12
|
+
headers.set("Location", location);
|
|
13
|
+
return new Response(null, {
|
|
14
|
+
...options,
|
|
15
|
+
status: options.status ?? 302,
|
|
16
|
+
headers
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function isRouteErrorResponse(value) {
|
|
20
|
+
return value instanceof Error && "status" in value;
|
|
21
|
+
}
|
|
22
|
+
async function normalizeResult(value) {
|
|
23
|
+
if (value && typeof value === "object" && "__routeError" in value) {
|
|
24
|
+
const error = value.__routeError;
|
|
25
|
+
return Object.assign(Error(error.message), error);
|
|
26
|
+
}
|
|
27
|
+
if (value instanceof Response) {
|
|
28
|
+
if (value.headers.has("Location")) return value;
|
|
29
|
+
if (!value.ok) return Object.assign(Error(await value.text()), {
|
|
30
|
+
status: value.status,
|
|
31
|
+
statusText: value.statusText
|
|
32
|
+
});
|
|
33
|
+
return value.json();
|
|
34
|
+
}
|
|
35
|
+
if (value && typeof value === "object" && "__routeData" in value) return resolveData(value.value);
|
|
36
|
+
return resolveData(value);
|
|
37
|
+
}
|
|
38
|
+
async function resolveData(value) {
|
|
39
|
+
const resolved = await value;
|
|
40
|
+
if (Array.isArray(resolved)) return Promise.all(resolved.map(resolveData));
|
|
41
|
+
if (resolved && typeof resolved === "object" && Object.getPrototypeOf(resolved) === Object.prototype) {
|
|
42
|
+
const entries = await Promise.all(Object.entries(resolved).map(async ([key, field]) => [key, await resolveData(field)]));
|
|
43
|
+
return Object.fromEntries(entries);
|
|
44
|
+
}
|
|
45
|
+
return resolved;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { data, isRouteErrorResponse, normalizeResult, redirect, resolveData };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Route, Router, RouterOptions } from "./types.ts";
|
|
2
2
|
/** Create an isolated router. Use browser: true for browser history, or loadRouter for SSR. */
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function createDataRouter(routes: readonly Route[], options?: RouterOptions): Router;
|