exta2 0.0.1-beta.29

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.
@@ -0,0 +1,49 @@
1
+ import * as $exta_router from '$exta-router';
2
+ import { PageManifest } from '$exta-manifest';
3
+
4
+ declare global {
5
+ interface Window {
6
+ __EXTA_PAGEMAP__: Record<string, string>;
7
+ }
8
+ }
9
+ declare function loadPageData(page: string): Promise<any>;
10
+ declare function useLocation(): string;
11
+ declare function useURL(): URL;
12
+ declare function usePathname(): string;
13
+ declare function useSearchQuery(): URLSearchParams;
14
+ declare function useHash(): string;
15
+ declare function useRouter(): {
16
+ location: string;
17
+ push: (() => void) | ((path: any) => void);
18
+ replace: (() => void) | ((path: any) => void);
19
+ };
20
+ declare function useParams(): any;
21
+ declare class Router {
22
+ routes: PageManifest[];
23
+ layout: any;
24
+ error: any;
25
+ modules: Record<string, any>;
26
+ data: Map<string, any>;
27
+ loadedModules: Map<string, any>;
28
+ constructor(routes: PageManifest[]);
29
+ prefetch(url: string): Promise<void>;
30
+ getHref(page: PageManifest): string;
31
+ preload(page: PageManifest): void;
32
+ preloadAllPages(): void;
33
+ loadLayout(): Promise<any>;
34
+ loadError(): Promise<any>;
35
+ findPage(url: string): any;
36
+ goto(href: string): Promise<{
37
+ module: Record<string, any>;
38
+ data: any;
39
+ }>;
40
+ }
41
+ declare const router: Router;
42
+ declare global {
43
+ interface Window {
44
+ _exta_router: $exta_router.Router;
45
+ _exta_useRouter: typeof $exta_router.useRouter;
46
+ }
47
+ }
48
+
49
+ export { Router, loadPageData, router, useHash, useLocation, useParams, usePathname, useRouter, useSearchQuery, useURL };
package/dist/router.js ADDED
@@ -0,0 +1,270 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var router_exports = {};
29
+ __export(router_exports, {
30
+ Router: () => Router,
31
+ loadPageData: () => loadPageData,
32
+ router: () => router,
33
+ useHash: () => useHash,
34
+ useLocation: () => useLocation,
35
+ useParams: () => useParams,
36
+ usePathname: () => usePathname,
37
+ useRouter: () => useRouter,
38
+ useSearchQuery: () => useSearchQuery,
39
+ useURL: () => useURL
40
+ });
41
+ module.exports = __toCommonJS(router_exports);
42
+ var import_exta_manifest = require("$exta-manifest");
43
+ var import_exta_pages = __toESM(require("$exta-pages"), 1);
44
+ var import_react = __toESM(require("react"), 1);
45
+ var import_react2 = __toESM(require("react"), 1);
46
+ var import_react3 = __toESM(require("react"), 1);
47
+ const import_meta = {};
48
+ function normalizePath(path) {
49
+ path = path.replace(/\\/g, "/");
50
+ let parts = path.split("/").filter(Boolean), stack = [];
51
+ for (let part of parts)
52
+ part !== "." && (part === ".." ? stack.pop() : stack.push(part));
53
+ return "/" + stack.join("/");
54
+ }
55
+ function isSamePathClient(pathA, pathB) {
56
+ let normalizedA = normalizePath(pathA), normalizedB = normalizePath(pathB);
57
+ return normalizedA.toLowerCase() === normalizedB.toLowerCase();
58
+ }
59
+ function removeExtension(path) {
60
+ let lastDotIndex = path.lastIndexOf(".");
61
+ return lastDotIndex === -1 ? path : path.slice(0, lastDotIndex);
62
+ }
63
+ var DefaultLayout = ({ children }) => import_react2.default.createElement(import_react2.default.Fragment, null, children);
64
+ var containerStyle = {
65
+ display: "flex",
66
+ justifyContent: "center",
67
+ alignItems: "center",
68
+ width: "100%",
69
+ height: "100vh",
70
+ textAlign: "center",
71
+ flexDirection: "column"
72
+ }, defaultProps = {
73
+ status: 404,
74
+ message: "Page not found"
75
+ }, DefaultError = ({ status, message } = defaultProps) => (status = status ?? defaultProps.status, message = message ?? defaultProps.message, import_react3.default.createElement("div", { style: containerStyle }, [
76
+ import_react3.default.createElement("h1", { key: "status" }, String(status)),
77
+ import_react3.default.createElement("p", { key: "message" }, message)
78
+ ]));
79
+ function matchUrlToRoute(url, routeResult) {
80
+ let { regex, params } = routeResult, match = regex.exec(url);
81
+ if (!match)
82
+ return null;
83
+ let result = {};
84
+ for (let i = 0; i < params.length; i++) {
85
+ let paramName = params[i], capturedValue = match[i + 1];
86
+ if (paramName.startsWith("..."))
87
+ throw new Error(
88
+ "[... file names are not supported due to static data generation issues."
89
+ );
90
+ result[paramName] = capturedValue;
91
+ }
92
+ return result;
93
+ }
94
+ var findPage = (url, _manifest_object) => {
95
+ let sortedManifest = [..._manifest_object].sort(
96
+ (a, b) => a.params.length - b.params.length
97
+ );
98
+ for (let route of sortedManifest)
99
+ if (route.regexp.test(decodeURIComponent(url)) && !route.path.startsWith("[") && !route.path.endsWith("]"))
100
+ return route;
101
+ return null;
102
+ };
103
+ var isServerSide = typeof window > "u", staticManifest = isServerSide ? {} : JSON.parse(document.getElementById("__STATIC_MANIFEST__")?.innerText || "{}");
104
+ function prettyURL(path) {
105
+ return path === "." && (path = ""), path.startsWith("/") || (path = `/${path}`), path.endsWith("/") && (path = path.slice(0, -1)), path;
106
+ }
107
+ async function loadPageData(page) {
108
+ if (import_meta.env.DEV)
109
+ return await (await fetch(`/.exta/__page_data?page=${page}`)).json();
110
+ {
111
+ let id = staticManifest[page.replace(/\//g, "_") + ".json"];
112
+ if (id === null)
113
+ return { props: {} };
114
+ if (id === void 0)
115
+ return { props: {}, status: 404 };
116
+ let target = `/data/${id}.json`;
117
+ try {
118
+ return { props: await (await fetch(target)).json() };
119
+ } catch (__e) {
120
+ return console.error(`Cannot find page (fetching ${target}) - ${__e.message}`), { props: {}, status: 404 };
121
+ }
122
+ }
123
+ }
124
+ function createHistoryStore() {
125
+ if (isServerSide)
126
+ return {
127
+ subscribe() {
128
+ return () => {
129
+ };
130
+ },
131
+ getSnapshot() {
132
+ return global.__EXTA_SSR_DATA__.pathname;
133
+ },
134
+ push() {
135
+ },
136
+ replace() {
137
+ }
138
+ };
139
+ let listeners = /* @__PURE__ */ new Set(), notify = () => {
140
+ for (let l of listeners)
141
+ l();
142
+ }, wrap = (method) => {
143
+ let original = history[method];
144
+ return function(...args) {
145
+ original.apply(this, args), notify();
146
+ };
147
+ };
148
+ return history.pushState = wrap("pushState"), history.replaceState = wrap("replaceState"), window.addEventListener("popstate", notify), {
149
+ subscribe(listener) {
150
+ return listeners.add(listener), () => listeners.delete(listener);
151
+ },
152
+ getSnapshot() {
153
+ return decodeURIComponent(
154
+ window.location.pathname + window.location.search + window.location.hash
155
+ );
156
+ },
157
+ push(path) {
158
+ if (path.startsWith("#")) {
159
+ location.hash = path;
160
+ return;
161
+ }
162
+ history.pushState({}, "", path), notify();
163
+ },
164
+ replace(path) {
165
+ history.replaceState({}, "", path), notify();
166
+ }
167
+ };
168
+ }
169
+ var historyStore = createHistoryStore();
170
+ function useLocationSelector(selector) {
171
+ return isServerSide ? selector(global.__EXTA_SSR_DATA__.pathname || "/.exta/ssr:unknown") : import_react.default.useSyncExternalStore(
172
+ historyStore.subscribe,
173
+ () => selector(historyStore.getSnapshot()),
174
+ () => selector(global?.__EXTA_SSR_DATA__?.pathname || "/.exta/ssr:unknown")
175
+ );
176
+ }
177
+ function useLocation() {
178
+ return useLocationSelector((url) => url);
179
+ }
180
+ function useURL() {
181
+ let url = useLocation();
182
+ return import_react.default.useMemo(() => new URL(url, "http://localhost"), [url]);
183
+ }
184
+ function usePathname() {
185
+ return useLocationSelector((url) => new URL(url, "http://localhost").pathname);
186
+ }
187
+ function useSearchQuery() {
188
+ let search = useLocationSelector((url) => new URL(url, "http://localhost").search);
189
+ return import_react.default.useMemo(() => new URLSearchParams(search), [search]);
190
+ }
191
+ function useHash() {
192
+ return useLocationSelector((url) => new URL(url, "http://localhost").hash);
193
+ }
194
+ function useRouter() {
195
+ return {
196
+ location: useLocation(),
197
+ push: historyStore.push,
198
+ replace: historyStore.replace
199
+ };
200
+ }
201
+ function useParams() {
202
+ if (isServerSide)
203
+ return global.__EXTA_SSR_DATA__.params || {};
204
+ let location2 = usePathname(), page = window._exta_router.findPage(location2);
205
+ if (!page) {
206
+ let message = `[exta-router] Cannot generate params: Route match for "${location2}" is missing required data.`;
207
+ throw new Error(message);
208
+ }
209
+ return matchUrlToRoute(location2, { params: page.params, regex: page.regexp });
210
+ }
211
+ var Router = class {
212
+ routes;
213
+ // layout component
214
+ layout;
215
+ // error page
216
+ error;
217
+ modules = {};
218
+ data = /* @__PURE__ */ new Map();
219
+ loadedModules = /* @__PURE__ */ new Map();
220
+ constructor(routes) {
221
+ this.routes = routes;
222
+ }
223
+ async prefetch(url) {
224
+ let _url = prettyURL(url);
225
+ this.data.has(_url) || this.data.set(_url, await loadPageData(url));
226
+ }
227
+ getHref(page) {
228
+ if (import_meta.env.DEV)
229
+ return `/.exta/${page.buildPath.replace(/\\/g, "/")}`;
230
+ let windowObject = window.__EXTA_PAGEMAP__;
231
+ for (let pageMapKey in windowObject)
232
+ if (isSamePathClient(removeExtension(pageMapKey), removeExtension(page.originalPath)))
233
+ return `/${windowObject[pageMapKey]}`;
234
+ }
235
+ preload(page) {
236
+ let href = this.getHref(page);
237
+ if (!href)
238
+ return;
239
+ let preloaded = document.getElementsByTagName("link");
240
+ for (let preloadScript of [...preloaded])
241
+ if (preloadScript.href === new URL(href, window.location.origin).href)
242
+ return;
243
+ let preload = document.createElement("link");
244
+ preload.rel = "prefetch", preload.href = href, document.head.appendChild(preload);
245
+ }
246
+ preloadAllPages() {
247
+ for (let route of this.routes)
248
+ this.preload(route);
249
+ }
250
+ async loadLayout() {
251
+ return this.layout ? this.layout : (import_exta_pages.default["[layout]"] ? this.layout = await import_exta_pages.default["[layout]"]() : this.layout = { _page: DefaultLayout }, this.layout);
252
+ }
253
+ async loadError() {
254
+ return this.error ? this.error : (import_exta_pages.default["[error]"] ? this.error = await import_exta_pages.default["[error]"]() : this.error = { _page: DefaultError }, this.error);
255
+ }
256
+ findPage(url) {
257
+ return url = url.toLowerCase(), findPage(url, this.routes);
258
+ }
259
+ async goto(href) {
260
+ let url = decodeURIComponent(
261
+ new URL(href, window.location.origin).pathname
262
+ ).toLowerCase(), page = this.findPage(url);
263
+ if (await this.loadLayout(), await this.loadError(), !page)
264
+ return;
265
+ let pageModule = this.loadedModules.has(page.path) ? this.loadedModules.get(page.path) : this.loadedModules.set(page.path, await import_exta_pages.default[page.path]()).get(page.path), _url = prettyURL(url), data = this.data.has(_url) ? this.data.get(_url) : this.data.set(_url, await loadPageData(url)).get(_url);
266
+ if (this.modules[page.path] = pageModule, data?.status !== 404)
267
+ return { module: this.modules, data };
268
+ }
269
+ }, router = new Router(import_exta_manifest.PAGES_MANIFEST);
270
+ isServerSide || (window._exta_router = router, window._exta_useRouter = useRouter);
@@ -0,0 +1,253 @@
1
+ // packages/exta/src/client/router.ts
2
+ import { PAGES_MANIFEST as manifest } from "$exta-manifest";
3
+ import pages from "$exta-pages";
4
+ import React3 from "react";
5
+
6
+ // packages/exta/src/utils/clientPath.ts
7
+ function normalizePath(path) {
8
+ path = path.replace(/\\/g, "/");
9
+ let parts = path.split("/").filter(Boolean), stack = [];
10
+ for (let part of parts)
11
+ part !== "." && (part === ".." ? stack.pop() : stack.push(part));
12
+ return "/" + stack.join("/");
13
+ }
14
+ function isSamePathClient(pathA, pathB) {
15
+ let normalizedA = normalizePath(pathA), normalizedB = normalizePath(pathB);
16
+ return normalizedA.toLowerCase() === normalizedB.toLowerCase();
17
+ }
18
+ function removeExtension(path) {
19
+ let lastDotIndex = path.lastIndexOf(".");
20
+ return lastDotIndex === -1 ? path : path.slice(0, lastDotIndex);
21
+ }
22
+
23
+ // packages/exta/src/client/components/_layout..ts
24
+ import React from "react";
25
+ var DefaultLayout = ({ children }) => React.createElement(React.Fragment, null, children);
26
+
27
+ // packages/exta/src/client/components/_error.ts
28
+ import React2 from "react";
29
+ var containerStyle = {
30
+ display: "flex",
31
+ justifyContent: "center",
32
+ alignItems: "center",
33
+ width: "100%",
34
+ height: "100vh",
35
+ textAlign: "center",
36
+ flexDirection: "column"
37
+ }, defaultProps = {
38
+ status: 404,
39
+ message: "Page not found"
40
+ }, DefaultError = ({ status, message } = defaultProps) => (status = status ?? defaultProps.status, message = message ?? defaultProps.message, React2.createElement("div", { style: containerStyle }, [
41
+ React2.createElement("h1", { key: "status" }, String(status)),
42
+ React2.createElement("p", { key: "message" }, message)
43
+ ]));
44
+
45
+ // packages/exta/src/utils/params.ts
46
+ function matchUrlToRoute(url, routeResult) {
47
+ let { regex, params } = routeResult, match = regex.exec(url);
48
+ if (!match)
49
+ return null;
50
+ let result = {};
51
+ for (let i = 0; i < params.length; i++) {
52
+ let paramName = params[i], capturedValue = match[i + 1];
53
+ if (paramName.startsWith("..."))
54
+ throw new Error(
55
+ "[... file names are not supported due to static data generation issues."
56
+ );
57
+ result[paramName] = capturedValue;
58
+ }
59
+ return result;
60
+ }
61
+
62
+ // packages/exta/src/utils/find.ts
63
+ var findPage = (url, _manifest_object) => {
64
+ let sortedManifest = [..._manifest_object].sort(
65
+ (a, b) => a.params.length - b.params.length
66
+ );
67
+ for (let route of sortedManifest)
68
+ if (route.regexp.test(decodeURIComponent(url)) && !route.path.startsWith("[") && !route.path.endsWith("]"))
69
+ return route;
70
+ return null;
71
+ };
72
+
73
+ // packages/exta/src/client/router.ts
74
+ var isServerSide = typeof window > "u", staticManifest = isServerSide ? {} : JSON.parse(document.getElementById("__STATIC_MANIFEST__")?.innerText || "{}");
75
+ function prettyURL(path) {
76
+ return path === "." && (path = ""), path.startsWith("/") || (path = `/${path}`), path.endsWith("/") && (path = path.slice(0, -1)), path;
77
+ }
78
+ async function loadPageData(page) {
79
+ if (import.meta.env.DEV)
80
+ return await (await fetch(`/.exta/__page_data?page=${page}`)).json();
81
+ {
82
+ let id = staticManifest[page.replace(/\//g, "_") + ".json"];
83
+ if (id === null)
84
+ return { props: {} };
85
+ if (id === void 0)
86
+ return { props: {}, status: 404 };
87
+ let target = `/data/${id}.json`;
88
+ try {
89
+ return { props: await (await fetch(target)).json() };
90
+ } catch (__e) {
91
+ return console.error(`Cannot find page (fetching ${target}) - ${__e.message}`), { props: {}, status: 404 };
92
+ }
93
+ }
94
+ }
95
+ function createHistoryStore() {
96
+ if (isServerSide)
97
+ return {
98
+ subscribe() {
99
+ return () => {
100
+ };
101
+ },
102
+ getSnapshot() {
103
+ return global.__EXTA_SSR_DATA__.pathname;
104
+ },
105
+ push() {
106
+ },
107
+ replace() {
108
+ }
109
+ };
110
+ let listeners = /* @__PURE__ */ new Set(), notify = () => {
111
+ for (let l of listeners)
112
+ l();
113
+ }, wrap = (method) => {
114
+ let original = history[method];
115
+ return function(...args) {
116
+ original.apply(this, args), notify();
117
+ };
118
+ };
119
+ return history.pushState = wrap("pushState"), history.replaceState = wrap("replaceState"), window.addEventListener("popstate", notify), {
120
+ subscribe(listener) {
121
+ return listeners.add(listener), () => listeners.delete(listener);
122
+ },
123
+ getSnapshot() {
124
+ return decodeURIComponent(
125
+ window.location.pathname + window.location.search + window.location.hash
126
+ );
127
+ },
128
+ push(path) {
129
+ if (path.startsWith("#")) {
130
+ location.hash = path;
131
+ return;
132
+ }
133
+ history.pushState({}, "", path), notify();
134
+ },
135
+ replace(path) {
136
+ history.replaceState({}, "", path), notify();
137
+ }
138
+ };
139
+ }
140
+ var historyStore = createHistoryStore();
141
+ function useLocationSelector(selector) {
142
+ return isServerSide ? selector(global.__EXTA_SSR_DATA__.pathname || "/.exta/ssr:unknown") : React3.useSyncExternalStore(
143
+ historyStore.subscribe,
144
+ () => selector(historyStore.getSnapshot()),
145
+ () => selector(global?.__EXTA_SSR_DATA__?.pathname || "/.exta/ssr:unknown")
146
+ );
147
+ }
148
+ function useLocation() {
149
+ return useLocationSelector((url) => url);
150
+ }
151
+ function useURL() {
152
+ let url = useLocation();
153
+ return React3.useMemo(() => new URL(url, "http://localhost"), [url]);
154
+ }
155
+ function usePathname() {
156
+ return useLocationSelector((url) => new URL(url, "http://localhost").pathname);
157
+ }
158
+ function useSearchQuery() {
159
+ let search = useLocationSelector((url) => new URL(url, "http://localhost").search);
160
+ return React3.useMemo(() => new URLSearchParams(search), [search]);
161
+ }
162
+ function useHash() {
163
+ return useLocationSelector((url) => new URL(url, "http://localhost").hash);
164
+ }
165
+ function useRouter() {
166
+ return {
167
+ location: useLocation(),
168
+ push: historyStore.push,
169
+ replace: historyStore.replace
170
+ };
171
+ }
172
+ function useParams() {
173
+ if (isServerSide)
174
+ return global.__EXTA_SSR_DATA__.params || {};
175
+ let location2 = usePathname(), page = window._exta_router.findPage(location2);
176
+ if (!page) {
177
+ let message = `[exta-router] Cannot generate params: Route match for "${location2}" is missing required data.`;
178
+ throw new Error(message);
179
+ }
180
+ return matchUrlToRoute(location2, { params: page.params, regex: page.regexp });
181
+ }
182
+ var Router = class {
183
+ routes;
184
+ // layout component
185
+ layout;
186
+ // error page
187
+ error;
188
+ modules = {};
189
+ data = /* @__PURE__ */ new Map();
190
+ loadedModules = /* @__PURE__ */ new Map();
191
+ constructor(routes) {
192
+ this.routes = routes;
193
+ }
194
+ async prefetch(url) {
195
+ let _url = prettyURL(url);
196
+ this.data.has(_url) || this.data.set(_url, await loadPageData(url));
197
+ }
198
+ getHref(page) {
199
+ if (import.meta.env.DEV)
200
+ return `/.exta/${page.buildPath.replace(/\\/g, "/")}`;
201
+ let windowObject = window.__EXTA_PAGEMAP__;
202
+ for (let pageMapKey in windowObject)
203
+ if (isSamePathClient(removeExtension(pageMapKey), removeExtension(page.originalPath)))
204
+ return `/${windowObject[pageMapKey]}`;
205
+ }
206
+ preload(page) {
207
+ let href = this.getHref(page);
208
+ if (!href)
209
+ return;
210
+ let preloaded = document.getElementsByTagName("link");
211
+ for (let preloadScript of [...preloaded])
212
+ if (preloadScript.href === new URL(href, window.location.origin).href)
213
+ return;
214
+ let preload = document.createElement("link");
215
+ preload.rel = "prefetch", preload.href = href, document.head.appendChild(preload);
216
+ }
217
+ preloadAllPages() {
218
+ for (let route of this.routes)
219
+ this.preload(route);
220
+ }
221
+ async loadLayout() {
222
+ return this.layout ? this.layout : (pages["[layout]"] ? this.layout = await pages["[layout]"]() : this.layout = { _page: DefaultLayout }, this.layout);
223
+ }
224
+ async loadError() {
225
+ return this.error ? this.error : (pages["[error]"] ? this.error = await pages["[error]"]() : this.error = { _page: DefaultError }, this.error);
226
+ }
227
+ findPage(url) {
228
+ return url = url.toLowerCase(), findPage(url, this.routes);
229
+ }
230
+ async goto(href) {
231
+ let url = decodeURIComponent(
232
+ new URL(href, window.location.origin).pathname
233
+ ).toLowerCase(), page = this.findPage(url);
234
+ if (await this.loadLayout(), await this.loadError(), !page)
235
+ return;
236
+ let pageModule = this.loadedModules.has(page.path) ? this.loadedModules.get(page.path) : this.loadedModules.set(page.path, await pages[page.path]()).get(page.path), _url = prettyURL(url), data = this.data.has(_url) ? this.data.get(_url) : this.data.set(_url, await loadPageData(url)).get(_url);
237
+ if (this.modules[page.path] = pageModule, data?.status !== 404)
238
+ return { module: this.modules, data };
239
+ }
240
+ }, router = new Router(manifest);
241
+ isServerSide || (window._exta_router = router, window._exta_useRouter = useRouter);
242
+ export {
243
+ Router,
244
+ loadPageData,
245
+ router,
246
+ useHash,
247
+ useLocation,
248
+ useParams,
249
+ usePathname,
250
+ useRouter,
251
+ useSearchQuery,
252
+ useURL
253
+ };