olova-router 1.0.19 → 1.0.21

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,272 @@
1
+ import { OlovaComponent, OlovaProps } from 'olova/runtime';
2
+ import './history.js';
3
+ import './lazy.js';
4
+
5
+ declare const _default: OlovaComponent;
6
+
7
+ type Breadcrumb = {
8
+ label: string;
9
+ path: string;
10
+ name?: string;
11
+ };
12
+ declare function generateBreadcrumbs(location: RouteLocation, labelMap?: Record<string, string>): Breadcrumb[];
13
+ declare function generateBreadcrumbsFromMatches(matches: RouteMatchInfo[], labelMap?: Record<string, string>): Breadcrumb[];
14
+
15
+ type GuardCondition = (context: RouteGuardContext) => boolean | Promise<boolean>;
16
+ declare function createConditionalGuard(condition: GuardCondition, redirectTo?: RouteTarget): (context: RouteGuardContext) => Promise<RouteGuardResult>;
17
+ declare function createParamGuard(paramName: string, validator: (value: string) => boolean | Promise<boolean>, redirectTo?: RouteTarget): (context: RouteGuardContext) => Promise<RouteGuardResult>;
18
+ declare function createQueryGuard(queryKey: string, validator: (value: string | string[] | undefined) => boolean | Promise<boolean>, redirectTo?: RouteTarget): (context: RouteGuardContext) => Promise<RouteGuardResult>;
19
+ declare function createCompositeGuard(guards: Array<(context: RouteGuardContext) => RouteGuardResult | Promise<RouteGuardResult>>): (context: RouteGuardContext) => Promise<RouteGuardResult>;
20
+ declare function createDebounceGuard(guard: (context: RouteGuardContext) => RouteGuardResult | Promise<RouteGuardResult>, delayMs?: number): (context: RouteGuardContext) => Promise<RouteGuardResult>;
21
+
22
+ type Middleware = (context: RouteGuardContext) => RouteGuardResult | Promise<RouteGuardResult>;
23
+ type MiddlewareChain = {
24
+ use: (middleware: Middleware) => MiddlewareChain;
25
+ execute: (context: RouteGuardContext) => Promise<RouteGuardResult>;
26
+ };
27
+ declare function createMiddlewareChain(): MiddlewareChain;
28
+ declare function createAuthMiddleware(isAuthenticated: () => boolean, redirectTo?: string): Middleware;
29
+ declare function createRoleMiddleware(userRole: () => string | null, allowedRoles: string[], redirectTo?: string): Middleware;
30
+ declare function createAnalyticsMiddleware(trackPageView: (path: string) => void): Middleware;
31
+ declare function createScrollMiddleware(scrollToTop?: boolean): Middleware;
32
+
33
+ type PrefetchOptions = {
34
+ priority?: "high" | "low";
35
+ };
36
+ declare function prefetchRoute(to: RouteTarget, options?: PrefetchOptions): void;
37
+ declare function isPrefetched(to: RouteTarget): boolean;
38
+ declare function clearPrefetchCache(): void;
39
+
40
+ declare function useSearchParams(): {
41
+ get: (name: string) => string | null;
42
+ getAll: (name: string) => string[];
43
+ has: (name: string) => boolean;
44
+ keys: () => string[];
45
+ values: () => string[];
46
+ entries: () => Array<[string, string]>;
47
+ toString: () => string;
48
+ };
49
+ declare function usePathname(): string;
50
+ declare function useHash(): string;
51
+ declare function clearSearchParamsCache(): void;
52
+
53
+ type TransitionState = "idle" | "pending" | "success" | "error";
54
+ type TransitionOptions = {
55
+ onStart?: () => void;
56
+ onSuccess?: () => void;
57
+ onError?: (error: Error) => void;
58
+ };
59
+ declare function useTransition(): {
60
+ isPending: boolean;
61
+ state: TransitionState;
62
+ error: Error | null;
63
+ };
64
+ declare function startTransition(callback: () => void | Promise<void>, options?: TransitionOptions): void;
65
+ declare function resetTransition(): void;
66
+
67
+ type ErrorBoundaryState = {
68
+ hasError: boolean;
69
+ error: Error | null;
70
+ };
71
+ declare function captureError(error: Error): void;
72
+ declare function clearError(): void;
73
+ declare function getErrorBoundaryState(): ErrorBoundaryState;
74
+ declare function hasError(): boolean;
75
+ declare function getError(): Error | null;
76
+
77
+ type RouteMetadata = {
78
+ title?: string;
79
+ description?: string;
80
+ keywords?: string[];
81
+ author?: string;
82
+ robots?: string;
83
+ viewport?: string;
84
+ charset?: string;
85
+ ogTitle?: string;
86
+ ogDescription?: string;
87
+ ogImage?: string;
88
+ ogUrl?: string;
89
+ ogType?: string;
90
+ twitterCard?: string;
91
+ twitterTitle?: string;
92
+ twitterDescription?: string;
93
+ twitterImage?: string;
94
+ twitterCreator?: string;
95
+ canonical?: string;
96
+ [key: string]: unknown;
97
+ };
98
+ type MetadataGenerator = (location: RouteLocation) => RouteMetadata | Promise<RouteMetadata>;
99
+ declare function registerRouteMetadata(path: string, metadata: RouteMetadata | MetadataGenerator): void;
100
+ declare function getRouteMetadata(location: RouteLocation): Promise<RouteMetadata>;
101
+ declare function applyMetadata(metadata: RouteMetadata): void;
102
+ declare function clearMetadataCache(): void;
103
+
104
+ type RoutePattern = {
105
+ pattern: string;
106
+ isDynamic: boolean;
107
+ isCatchAll: boolean;
108
+ isOptionalCatchAll: boolean;
109
+ paramNames: string[];
110
+ };
111
+ declare function parseRoutePattern(path: string): RoutePattern;
112
+ declare function matchDynamicRoute(pattern: string, pathname: string): RouteParams | null;
113
+ declare function buildDynamicPath(pattern: string, params: RouteParams): string;
114
+
115
+ type RouteGroup = {
116
+ name: string;
117
+ routes: RouteObject[];
118
+ layout?: OlovaComponent;
119
+ metadata?: Record<string, unknown>;
120
+ };
121
+ declare function createRouteGroup(name: string, routes: RouteObject[], options?: {
122
+ layout?: OlovaComponent;
123
+ metadata?: Record<string, unknown>;
124
+ }): RouteGroup;
125
+ declare function getRouteGroup(name: string): RouteGroup | undefined;
126
+ declare function getAllRouteGroups(): RouteGroup[];
127
+ declare function removeRouteGroup(name: string): boolean;
128
+ declare function mergeRouteGroups(...groupNames: string[]): RouteObject[];
129
+ declare function clearRouteGroups(): void;
130
+
131
+ type Slot = {
132
+ name: string;
133
+ component: OlovaComponent;
134
+ props?: OlovaProps;
135
+ };
136
+ type ParallelRoutesConfig = {
137
+ slots: Record<string, OlovaComponent>;
138
+ defaultSlots?: Record<string, OlovaComponent>;
139
+ };
140
+ declare function createParallelRoutes(config: ParallelRoutesConfig): OlovaComponent;
141
+ declare function useSlot(slotName: string): OlovaComponent | null;
142
+ declare function renderSlot(slot: Slot): OlovaComponent;
143
+ declare function conditionalSlot(condition: boolean, trueSlot: OlovaComponent, falseSlot?: OlovaComponent): OlovaComponent;
144
+
145
+ type InterceptRule = {
146
+ pattern: string;
147
+ interceptor: string;
148
+ level: "same" | "parent" | "grandparent" | "root";
149
+ };
150
+ type InterceptConfig = {
151
+ rules: InterceptRule[];
152
+ };
153
+ declare function registerInterceptRule(id: string, rule: InterceptRule): void;
154
+ declare function getInterceptRule(id: string): InterceptRule | undefined;
155
+ declare function findInterceptor(pathname: string, currentPath: string): InterceptRule | null;
156
+ declare function removeInterceptRule(id: string): boolean;
157
+ declare function clearInterceptRules(): void;
158
+ declare function getAllInterceptRules(): InterceptRule[];
159
+
160
+ type RouterMode = "auto" | "history" | "hash";
161
+ type ResolvedMode = "history" | "hash";
162
+ type Primitive = string | number | boolean;
163
+ type RouteParams = Record<string, string>;
164
+ type RouteQueryValue = string | string[];
165
+ type RouteQuery = Record<string, RouteQueryValue>;
166
+ type RouteQueryInputValue = Primitive | Primitive[] | null | undefined;
167
+ type RouteQueryInput = Record<string, RouteQueryInputValue>;
168
+ type RouteTarget = string | {
169
+ name?: string;
170
+ path?: string;
171
+ params?: Record<string, Primitive>;
172
+ query?: RouteQueryInput;
173
+ hash?: string;
174
+ };
175
+ type NavigateOptions = {
176
+ replace?: boolean;
177
+ scroll?: boolean;
178
+ };
179
+ type MatchOptions = {
180
+ exact?: boolean;
181
+ };
182
+ type RouteMatchInfo = {
183
+ name?: string;
184
+ path: string;
185
+ meta?: unknown;
186
+ };
187
+ type RouteLocation = {
188
+ name?: string;
189
+ path: string;
190
+ fullPath: string;
191
+ href: string;
192
+ params: RouteParams;
193
+ query: RouteQuery;
194
+ hash: string;
195
+ meta?: unknown;
196
+ matchedPath: string;
197
+ matches: RouteMatchInfo[];
198
+ };
199
+ type RouteGuardContext = {
200
+ to: RouteLocation;
201
+ from: RouteLocation | null;
202
+ params: RouteParams;
203
+ query: RouteQuery;
204
+ };
205
+ type RouteGuardResult = boolean | string | RouteTarget | void;
206
+ type RouteGuard = (context: RouteGuardContext) => RouteGuardResult;
207
+ type RouteRedirect = RouteTarget | ((context: RouteGuardContext) => RouteTarget | null | undefined);
208
+ type RoutePropsFactory = OlovaProps | ((context: RouteGuardContext) => OlovaProps);
209
+ type RouteObject = {
210
+ path?: string;
211
+ index?: boolean;
212
+ component?: OlovaComponent;
213
+ redirect?: RouteRedirect;
214
+ props?: RoutePropsFactory;
215
+ beforeEnter?: RouteGuard;
216
+ name?: string;
217
+ meta?: unknown;
218
+ children?: RouteObject[];
219
+ };
220
+ type RouteDefinition = OlovaComponent | (Omit<RouteObject, "path" | "index"> & {
221
+ children?: RouteObject[];
222
+ });
223
+ type RouterRoutes = Record<string, RouteDefinition> | RouteObject[];
224
+ type RouterProps = {
225
+ routes: RouterRoutes;
226
+ mode?: RouterMode;
227
+ base?: string;
228
+ scroll?: boolean;
229
+ };
230
+ type RouteResolution = {
231
+ mode: ResolvedMode;
232
+ location: RouteLocation;
233
+ component: OlovaComponent;
234
+ props: OlovaProps;
235
+ };
236
+ type RouterApi = {
237
+ current: () => RouteResolution;
238
+ readonly mode: ResolvedMode;
239
+ readonly location: RouteLocation;
240
+ readonly path: string;
241
+ readonly fullPath: string;
242
+ readonly params: RouteParams;
243
+ readonly query: RouteQuery;
244
+ readonly hash: string;
245
+ readonly matchedPath: string;
246
+ readonly matches: RouteMatchInfo[];
247
+ push: (to: RouteTarget, options?: NavigateOptions) => void;
248
+ navigate: (to: RouteTarget, options?: NavigateOptions) => void;
249
+ replace: (to: RouteTarget, options?: Omit<NavigateOptions, "replace">) => void;
250
+ back: () => void;
251
+ forward: () => void;
252
+ refresh: () => void;
253
+ resolve: (to: RouteTarget) => string;
254
+ href: (to: RouteTarget) => string;
255
+ isActive: (to: RouteTarget, options?: MatchOptions) => boolean;
256
+ };
257
+
258
+ declare function matchPath(pattern: string, path: string): RouteParams | null;
259
+ declare function navigate(to: RouteTarget, options?: NavigateOptions): void;
260
+ declare function link(toOrEvent?: RouteTarget | Event, options?: NavigateOptions): ((event?: Event) => void) | void;
261
+ declare function useRouter(): RouterApi;
262
+ declare function useRoute(): RouteLocation;
263
+ declare function useParams(): RouteParams;
264
+ declare function useQuery(): RouteQuery;
265
+ declare function resolveHref(to: RouteTarget): string;
266
+ declare function isActiveHref(to: RouteTarget, options?: MatchOptions): boolean;
267
+ declare const Outlet: OlovaComponent;
268
+ declare const Router: OlovaComponent;
269
+ declare const BrowserRouter: OlovaComponent;
270
+ declare const HashRouter: OlovaComponent;
271
+
272
+ export { getRouteGroup as $, buildDynamicPath as A, BrowserRouter as B, type Breadcrumb, captureError as C, clearError as D, clearInterceptRules as E, clearMetadataCache as F, type GuardCondition as G, HashRouter as H, type InterceptConfig as I, clearPrefetchCache as J, clearRouteGroups as K, clearSearchParamsCache as L, type Middleware as M, type NavigateOptions as N, Outlet as O, conditionalSlot as P, createParallelRoutes as Q, type RouteDefinition as R, createRouteGroup as S, Router as T, findInterceptor as U, getAllInterceptRules as V, getAllRouteGroups as W, getError as X, getErrorBoundaryState as Y, getInterceptRule as Z, _default as _, createConditionalGuard as a, getRouteMetadata as a0, hasError as a1, isActiveHref as a2, isPrefetched as a3, link as a4, matchDynamicRoute as a5, matchPath as a6, mergeRouteGroups as a7, navigate as a8, parseRoutePattern as a9, prefetchRoute as aa, registerInterceptRule as ab, registerRouteMetadata as ac, removeInterceptRule as ad, removeRouteGroup as ae, renderSlot as af, resetTransition as ag, resolveHref as ah, startTransition as ai, useHash as aj, useParams as ak, usePathname as al, useQuery as am, useRoute as an, useRouter as ao, useSearchParams as ap, useSlot as aq, useTransition as ar, createDebounceGuard as b, createCompositeGuard as c, createParamGuard as d, createQueryGuard as e, type MiddlewareChain as f, createAnalyticsMiddleware as g, generateBreadcrumbs, generateBreadcrumbsFromMatches, createAuthMiddleware as h, createMiddlewareChain as i, createRoleMiddleware as j, createScrollMiddleware as k, type InterceptRule as l, type MatchOptions as m, type RouteGuardContext as n, type RouteGuardResult as o, type RouteLocation as p, type RouteMatchInfo as q, type RouteObject as r, type RouteParams as s, type RouteQuery as t, type RouteQueryInput as u, type RouteTarget as v, type RouterMode as w, type RouterProps as x, type RouterRoutes as y, applyMetadata as z };
@@ -0,0 +1,36 @@
1
+ // src/breadcrumbs.ts
2
+ function generateBreadcrumbs(location, labelMap) {
3
+ const breadcrumbs = [];
4
+ const segments = location.path.split("/").filter(Boolean);
5
+ breadcrumbs.push({
6
+ label: labelMap?.home ?? "Home",
7
+ path: "/",
8
+ name: "home"
9
+ });
10
+ let currentPath = "";
11
+ for (const segment of segments) {
12
+ currentPath += `/${segment}`;
13
+ const label = labelMap?.[segment] ?? segment.charAt(0).toUpperCase() + segment.slice(1);
14
+ breadcrumbs.push({
15
+ label,
16
+ path: currentPath
17
+ });
18
+ }
19
+ return breadcrumbs;
20
+ }
21
+ function generateBreadcrumbsFromMatches(matches, labelMap) {
22
+ const breadcrumbs = [];
23
+ for (const match of matches) {
24
+ const label = labelMap?.[match.name ?? ""] ?? match.name ?? match.path;
25
+ breadcrumbs.push({
26
+ label,
27
+ path: match.path,
28
+ name: match.name
29
+ });
30
+ }
31
+ return breadcrumbs;
32
+ }
33
+
34
+ export { generateBreadcrumbs, generateBreadcrumbsFromMatches };
35
+ //# sourceMappingURL=breadcrumbs.js.map
36
+ //# sourceMappingURL=breadcrumbs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/breadcrumbs.ts"],"names":[],"mappings":";AAQO,SAAS,mBAAA,CAAoB,UAAyB,QAAA,EAAiD;AAC5G,EAAA,MAAM,cAA4B,EAAC;AACnC,EAAA,MAAM,WAAW,QAAA,CAAS,IAAA,CAAK,MAAM,GAAG,CAAA,CAAE,OAAO,OAAO,CAAA;AAExD,EAAA,WAAA,CAAY,IAAA,CAAK;AAAA,IACf,KAAA,EAAO,UAAU,IAAA,IAAQ,MAAA;AAAA,IACzB,IAAA,EAAM,GAAA;AAAA,IACN,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,IAAI,WAAA,GAAc,EAAA;AAClB,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,WAAA,IAAe,IAAI,OAAO,CAAA,CAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,QAAA,GAAW,OAAO,CAAA,IAAK,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAY,GAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA;AAEtF,IAAA,WAAA,CAAY,IAAA,CAAK;AAAA,MACf,KAAA;AAAA,MACA,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,WAAA;AACT;AAEO,SAAS,8BAAA,CACd,SACA,QAAA,EACc;AACd,EAAA,MAAM,cAA4B,EAAC;AAEnC,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,MAAM,KAAA,GAAQ,WAAW,KAAA,CAAM,IAAA,IAAQ,EAAE,CAAA,IAAK,KAAA,CAAM,QAAQ,KAAA,CAAM,IAAA;AAClE,IAAA,WAAA,CAAY,IAAA,CAAK;AAAA,MACf,KAAA;AAAA,MACA,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,MAAM,KAAA,CAAM;AAAA,KACb,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,WAAA;AACT","file":"breadcrumbs.js","sourcesContent":["import type { RouteLocation, RouteMatchInfo } from \"./index\";\r\n\r\nexport type Breadcrumb = {\r\n label: string;\r\n path: string;\r\n name?: string;\r\n};\r\n\r\nexport function generateBreadcrumbs(location: RouteLocation, labelMap?: Record<string, string>): Breadcrumb[] {\r\n const breadcrumbs: Breadcrumb[] = [];\r\n const segments = location.path.split(\"/\").filter(Boolean);\r\n\r\n breadcrumbs.push({\r\n label: labelMap?.home ?? \"Home\",\r\n path: \"/\",\r\n name: \"home\",\r\n });\r\n\r\n let currentPath = \"\";\r\n for (const segment of segments) {\r\n currentPath += `/${segment}`;\r\n const label = labelMap?.[segment] ?? segment.charAt(0).toUpperCase() + segment.slice(1);\r\n\r\n breadcrumbs.push({\r\n label,\r\n path: currentPath,\r\n });\r\n }\r\n\r\n return breadcrumbs;\r\n}\r\n\r\nexport function generateBreadcrumbsFromMatches(\r\n matches: RouteMatchInfo[],\r\n labelMap?: Record<string, string>,\r\n): Breadcrumb[] {\r\n const breadcrumbs: Breadcrumb[] = [];\r\n\r\n for (const match of matches) {\r\n const label = labelMap?.[match.name ?? \"\"] ?? match.name ?? match.path;\r\n breadcrumbs.push({\r\n label,\r\n path: match.path,\r\n name: match.name,\r\n });\r\n }\r\n\r\n return breadcrumbs;\r\n}\r\n"]}
@@ -0,0 +1,4 @@
1
+ export { G as GuardCondition, c as createCompositeGuard, a as createConditionalGuard, b as createDebounceGuard, d as createParamGuard, e as createQueryGuard } from './breadcrumbs.js';
2
+ import 'olova/runtime';
3
+ import './history.js';
4
+ import './lazy.js';
package/dist/guards.js ADDED
@@ -0,0 +1,66 @@
1
+ // src/guards.ts
2
+ function createConditionalGuard(condition, redirectTo) {
3
+ return async (context) => {
4
+ const allowed = await condition(context);
5
+ if (!allowed && redirectTo) {
6
+ return redirectTo;
7
+ }
8
+ return allowed;
9
+ };
10
+ }
11
+ function createParamGuard(paramName, validator, redirectTo) {
12
+ return async (context) => {
13
+ const value = context.params[paramName];
14
+ if (!value) {
15
+ return redirectTo ? redirectTo : false;
16
+ }
17
+ const valid = await validator(value);
18
+ if (!valid && redirectTo) {
19
+ return redirectTo;
20
+ }
21
+ return valid;
22
+ };
23
+ }
24
+ function createQueryGuard(queryKey, validator, redirectTo) {
25
+ return async (context) => {
26
+ const value = context.query[queryKey];
27
+ const valid = await validator(value);
28
+ if (!valid && redirectTo) {
29
+ return redirectTo;
30
+ }
31
+ return valid;
32
+ };
33
+ }
34
+ function createCompositeGuard(guards) {
35
+ return async (context) => {
36
+ for (const guard of guards) {
37
+ const result = await guard(context);
38
+ if (result !== true && result !== void 0) {
39
+ return result;
40
+ }
41
+ }
42
+ return true;
43
+ };
44
+ }
45
+ function createDebounceGuard(guard, delayMs = 300) {
46
+ let timeoutId = null;
47
+ let lastContext = null;
48
+ return async (context) => {
49
+ lastContext = context;
50
+ return new Promise((resolve) => {
51
+ if (timeoutId) {
52
+ clearTimeout(timeoutId);
53
+ }
54
+ timeoutId = setTimeout(async () => {
55
+ if (lastContext === context) {
56
+ const result = await guard(context);
57
+ resolve(result);
58
+ }
59
+ }, delayMs);
60
+ });
61
+ };
62
+ }
63
+
64
+ export { createCompositeGuard, createConditionalGuard, createDebounceGuard, createParamGuard, createQueryGuard };
65
+ //# sourceMappingURL=guards.js.map
66
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/guards.ts"],"names":[],"mappings":";AAIO,SAAS,sBAAA,CACd,WACA,UAAA,EAC2D;AAC3D,EAAA,OAAO,OAAO,OAAA,KAAY;AACxB,IAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,OAAO,CAAA;AACvC,IAAA,IAAI,CAAC,WAAW,UAAA,EAAY;AAC1B,MAAA,OAAO,UAAA;AAAA,IACT;AACA,IAAA,OAAO,OAAA;AAAA,EACT,CAAA;AACF;AAEO,SAAS,gBAAA,CACd,SAAA,EACA,SAAA,EACA,UAAA,EAC2D;AAC3D,EAAA,OAAO,OAAO,OAAA,KAAY;AACxB,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAA,CAAO,SAAS,CAAA;AACtC,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,OAAO,aAAa,UAAA,GAAa,KAAA;AAAA,IACnC;AACA,IAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,CAAU,KAAK,CAAA;AACnC,IAAA,IAAI,CAAC,SAAS,UAAA,EAAY;AACxB,MAAA,OAAO,UAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AACF;AAEO,SAAS,gBAAA,CACd,QAAA,EACA,SAAA,EACA,UAAA,EAC2D;AAC3D,EAAA,OAAO,OAAO,OAAA,KAAY;AACxB,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,QAAQ,CAAA;AACpC,IAAA,MAAM,KAAA,GAAQ,MAAM,SAAA,CAAU,KAAK,CAAA;AACnC,IAAA,IAAI,CAAC,SAAS,UAAA,EAAY;AACxB,MAAA,OAAO,UAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AACF;AAEO,SAAS,qBACd,MAAA,EAC2D;AAC3D,EAAA,OAAO,OAAO,OAAA,KAAY;AACxB,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,OAAO,CAAA;AAClC,MAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,MAAA,EAAW;AAC3C,QAAA,OAAO,MAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AACF;AAEO,SAAS,mBAAA,CACd,KAAA,EACA,OAAA,GAAU,GAAA,EACiD;AAC3D,EAAA,IAAI,SAAA,GAAkD,IAAA;AACtD,EAAA,IAAI,WAAA,GAAwC,IAAA;AAE5C,EAAA,OAAO,OAAO,OAAA,KAAY;AACxB,IAAA,WAAA,GAAc,OAAA;AAEd,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,YAAA,CAAa,SAAS,CAAA;AAAA,MACxB;AAEA,MAAA,SAAA,GAAY,WAAW,YAAY;AACjC,QAAA,IAAI,gBAAgB,OAAA,EAAS;AAC3B,UAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM,OAAO,CAAA;AAClC,UAAA,OAAA,CAAQ,MAAM,CAAA;AAAA,QAChB;AAAA,MACF,GAAG,OAAO,CAAA;AAAA,IACZ,CAAC,CAAA;AAAA,EACH,CAAA;AACF","file":"guards.js","sourcesContent":["import type { RouteGuardContext, RouteGuardResult, RouteTarget } from \"./index\";\r\n\r\nexport type GuardCondition = (context: RouteGuardContext) => boolean | Promise<boolean>;\r\n\r\nexport function createConditionalGuard(\r\n condition: GuardCondition,\r\n redirectTo?: RouteTarget,\r\n): (context: RouteGuardContext) => Promise<RouteGuardResult> {\r\n return async (context) => {\r\n const allowed = await condition(context);\r\n if (!allowed && redirectTo) {\r\n return redirectTo;\r\n }\r\n return allowed;\r\n };\r\n}\r\n\r\nexport function createParamGuard(\r\n paramName: string,\r\n validator: (value: string) => boolean | Promise<boolean>,\r\n redirectTo?: RouteTarget,\r\n): (context: RouteGuardContext) => Promise<RouteGuardResult> {\r\n return async (context) => {\r\n const value = context.params[paramName];\r\n if (!value) {\r\n return redirectTo ? redirectTo : false;\r\n }\r\n const valid = await validator(value);\r\n if (!valid && redirectTo) {\r\n return redirectTo;\r\n }\r\n return valid;\r\n };\r\n}\r\n\r\nexport function createQueryGuard(\r\n queryKey: string,\r\n validator: (value: string | string[] | undefined) => boolean | Promise<boolean>,\r\n redirectTo?: RouteTarget,\r\n): (context: RouteGuardContext) => Promise<RouteGuardResult> {\r\n return async (context) => {\r\n const value = context.query[queryKey];\r\n const valid = await validator(value);\r\n if (!valid && redirectTo) {\r\n return redirectTo;\r\n }\r\n return valid;\r\n };\r\n}\r\n\r\nexport function createCompositeGuard(\r\n guards: Array<(context: RouteGuardContext) => RouteGuardResult | Promise<RouteGuardResult>>,\r\n): (context: RouteGuardContext) => Promise<RouteGuardResult> {\r\n return async (context) => {\r\n for (const guard of guards) {\r\n const result = await guard(context);\r\n if (result !== true && result !== undefined) {\r\n return result;\r\n }\r\n }\r\n return true;\r\n };\r\n}\r\n\r\nexport function createDebounceGuard(\r\n guard: (context: RouteGuardContext) => RouteGuardResult | Promise<RouteGuardResult>,\r\n delayMs = 300,\r\n): (context: RouteGuardContext) => Promise<RouteGuardResult> {\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\r\n let lastContext: RouteGuardContext | null = null;\r\n\r\n return async (context) => {\r\n lastContext = context;\r\n\r\n return new Promise((resolve) => {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n\r\n timeoutId = setTimeout(async () => {\r\n if (lastContext === context) {\r\n const result = await guard(context);\r\n resolve(result);\r\n }\r\n }, delayMs);\r\n });\r\n };\r\n}\r\n"]}
@@ -0,0 +1,17 @@
1
+ type HistoryEntry = {
2
+ path: string;
3
+ timestamp: number;
4
+ };
5
+ type RouterHistory = {
6
+ entries: HistoryEntry[];
7
+ current: number;
8
+ push: (path: string) => void;
9
+ back: () => HistoryEntry | null;
10
+ forward: () => HistoryEntry | null;
11
+ go: (delta: number) => HistoryEntry | null;
12
+ clear: () => void;
13
+ getHistory: () => HistoryEntry[];
14
+ };
15
+ declare function createRouterHistory(maxSize?: number): RouterHistory;
16
+
17
+ export { type HistoryEntry, type RouterHistory, createRouterHistory };
@@ -0,0 +1,51 @@
1
+ // src/history.ts
2
+ function createRouterHistory(maxSize = 50) {
3
+ const entries = [];
4
+ let current = -1;
5
+ return {
6
+ entries,
7
+ current,
8
+ push(path) {
9
+ entries.splice(current + 1);
10
+ entries.push({ path, timestamp: Date.now() });
11
+ if (entries.length > maxSize) {
12
+ entries.shift();
13
+ } else {
14
+ current++;
15
+ }
16
+ },
17
+ back() {
18
+ if (current > 0) {
19
+ current--;
20
+ return entries[current];
21
+ }
22
+ return null;
23
+ },
24
+ forward() {
25
+ if (current < entries.length - 1) {
26
+ current++;
27
+ return entries[current];
28
+ }
29
+ return null;
30
+ },
31
+ go(delta) {
32
+ const next = current + delta;
33
+ if (next >= 0 && next < entries.length) {
34
+ current = next;
35
+ return entries[current];
36
+ }
37
+ return null;
38
+ },
39
+ clear() {
40
+ entries.length = 0;
41
+ current = -1;
42
+ },
43
+ getHistory() {
44
+ return [...entries];
45
+ }
46
+ };
47
+ }
48
+
49
+ export { createRouterHistory };
50
+ //# sourceMappingURL=history.js.map
51
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/history.ts"],"names":[],"mappings":";AAgBO,SAAS,mBAAA,CAAoB,UAAU,EAAA,EAAmB;AAC/D,EAAA,MAAM,UAA0B,EAAC;AACjC,EAAA,IAAI,OAAA,GAAU,EAAA;AAEd,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA;AAAA,IACA,KAAK,IAAA,EAAc;AACjB,MAAA,OAAA,CAAQ,MAAA,CAAO,UAAU,CAAC,CAAA;AAC1B,MAAA,OAAA,CAAQ,KAAK,EAAE,IAAA,EAAM,WAAW,IAAA,CAAK,GAAA,IAAO,CAAA;AAC5C,MAAA,IAAI,OAAA,CAAQ,SAAS,OAAA,EAAS;AAC5B,QAAA,OAAA,CAAQ,KAAA,EAAM;AAAA,MAChB,CAAA,MAAO;AACL,QAAA,OAAA,EAAA;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,IAAA,GAAO;AACL,MAAA,IAAI,UAAU,CAAA,EAAG;AACf,QAAA,OAAA,EAAA;AACA,QAAA,OAAO,QAAQ,OAAO,CAAA;AAAA,MACxB;AACA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,IAAI,OAAA,GAAU,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAChC,QAAA,OAAA,EAAA;AACA,QAAA,OAAO,QAAQ,OAAO,CAAA;AAAA,MACxB;AACA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,GAAG,KAAA,EAAe;AAChB,MAAA,MAAM,OAAO,OAAA,GAAU,KAAA;AACvB,MAAA,IAAI,IAAA,IAAQ,CAAA,IAAK,IAAA,GAAO,OAAA,CAAQ,MAAA,EAAQ;AACtC,QAAA,OAAA,GAAU,IAAA;AACV,QAAA,OAAO,QAAQ,OAAO,CAAA;AAAA,MACxB;AACA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,KAAA,GAAQ;AACN,MAAA,OAAA,CAAQ,MAAA,GAAS,CAAA;AACjB,MAAA,OAAA,GAAU,EAAA;AAAA,IACZ,CAAA;AAAA,IACA,UAAA,GAAa;AACX,MAAA,OAAO,CAAC,GAAG,OAAO,CAAA;AAAA,IACpB;AAAA,GACF;AACF","file":"history.js","sourcesContent":["export type HistoryEntry = {\r\n path: string;\r\n timestamp: number;\r\n};\r\n\r\nexport type RouterHistory = {\r\n entries: HistoryEntry[];\r\n current: number;\r\n push: (path: string) => void;\r\n back: () => HistoryEntry | null;\r\n forward: () => HistoryEntry | null;\r\n go: (delta: number) => HistoryEntry | null;\r\n clear: () => void;\r\n getHistory: () => HistoryEntry[];\r\n};\r\n\r\nexport function createRouterHistory(maxSize = 50): RouterHistory {\r\n const entries: HistoryEntry[] = [];\r\n let current = -1;\r\n\r\n return {\r\n entries,\r\n current,\r\n push(path: string) {\r\n entries.splice(current + 1);\r\n entries.push({ path, timestamp: Date.now() });\r\n if (entries.length > maxSize) {\r\n entries.shift();\r\n } else {\r\n current++;\r\n }\r\n },\r\n back() {\r\n if (current > 0) {\r\n current--;\r\n return entries[current];\r\n }\r\n return null;\r\n },\r\n forward() {\r\n if (current < entries.length - 1) {\r\n current++;\r\n return entries[current];\r\n }\r\n return null;\r\n },\r\n go(delta: number) {\r\n const next = current + delta;\r\n if (next >= 0 && next < entries.length) {\r\n current = next;\r\n return entries[current];\r\n }\r\n return null;\r\n },\r\n clear() {\r\n entries.length = 0;\r\n current = -1;\r\n },\r\n getHistory() {\r\n return [...entries];\r\n },\r\n };\r\n}\r\n"]}
package/dist/index.d.ts CHANGED
@@ -1,117 +1,4 @@
1
- import { OlovaComponent, OlovaProps } from 'olova/runtime';
2
-
3
- declare const _default: OlovaComponent;
4
-
5
- type RouterMode = "auto" | "history" | "hash";
6
- type ResolvedMode = "history" | "hash";
7
- type Primitive = string | number | boolean;
8
- type RouteParams = Record<string, string>;
9
- type RouteQueryValue = string | string[];
10
- type RouteQuery = Record<string, RouteQueryValue>;
11
- type RouteQueryInputValue = Primitive | Primitive[] | null | undefined;
12
- type RouteQueryInput = Record<string, RouteQueryInputValue>;
13
- type RouteTarget = string | {
14
- name?: string;
15
- path?: string;
16
- params?: Record<string, Primitive>;
17
- query?: RouteQueryInput;
18
- hash?: string;
19
- };
20
- type NavigateOptions = {
21
- replace?: boolean;
22
- scroll?: boolean;
23
- };
24
- type MatchOptions = {
25
- exact?: boolean;
26
- };
27
- type RouteMatchInfo = {
28
- name?: string;
29
- path: string;
30
- meta?: unknown;
31
- };
32
- type RouteLocation = {
33
- name?: string;
34
- path: string;
35
- fullPath: string;
36
- href: string;
37
- params: RouteParams;
38
- query: RouteQuery;
39
- hash: string;
40
- meta?: unknown;
41
- matchedPath: string;
42
- matches: RouteMatchInfo[];
43
- };
44
- type RouteGuardContext = {
45
- to: RouteLocation;
46
- from: RouteLocation | null;
47
- params: RouteParams;
48
- query: RouteQuery;
49
- };
50
- type RouteGuardResult = boolean | string | RouteTarget | void;
51
- type RouteGuard = (context: RouteGuardContext) => RouteGuardResult;
52
- type RouteRedirect = RouteTarget | ((context: RouteGuardContext) => RouteTarget | null | undefined);
53
- type RoutePropsFactory = OlovaProps | ((context: RouteGuardContext) => OlovaProps);
54
- type RouteObject = {
55
- path?: string;
56
- index?: boolean;
57
- component?: OlovaComponent;
58
- redirect?: RouteRedirect;
59
- props?: RoutePropsFactory;
60
- beforeEnter?: RouteGuard;
61
- name?: string;
62
- meta?: unknown;
63
- children?: RouteObject[];
64
- };
65
- type RouteDefinition = OlovaComponent | (Omit<RouteObject, "path" | "index"> & {
66
- children?: RouteObject[];
67
- });
68
- type RouterRoutes = Record<string, RouteDefinition> | RouteObject[];
69
- type RouterProps = {
70
- routes: RouterRoutes;
71
- mode?: RouterMode;
72
- base?: string;
73
- scroll?: boolean;
74
- };
75
- type RouteResolution = {
76
- mode: ResolvedMode;
77
- location: RouteLocation;
78
- component: OlovaComponent;
79
- props: OlovaProps;
80
- };
81
- type RouterApi = {
82
- current: () => RouteResolution;
83
- readonly mode: ResolvedMode;
84
- readonly location: RouteLocation;
85
- readonly path: string;
86
- readonly fullPath: string;
87
- readonly params: RouteParams;
88
- readonly query: RouteQuery;
89
- readonly hash: string;
90
- readonly matchedPath: string;
91
- readonly matches: RouteMatchInfo[];
92
- push: (to: RouteTarget, options?: NavigateOptions) => void;
93
- navigate: (to: RouteTarget, options?: NavigateOptions) => void;
94
- replace: (to: RouteTarget, options?: Omit<NavigateOptions, "replace">) => void;
95
- back: () => void;
96
- forward: () => void;
97
- refresh: () => void;
98
- resolve: (to: RouteTarget) => string;
99
- href: (to: RouteTarget) => string;
100
- isActive: (to: RouteTarget, options?: MatchOptions) => boolean;
101
- };
102
-
103
- declare function matchPath(pattern: string, path: string): RouteParams | null;
104
- declare function navigate(to: RouteTarget, options?: NavigateOptions): void;
105
- declare function link(toOrEvent?: RouteTarget | Event, options?: NavigateOptions): ((event?: Event) => void) | void;
106
- declare function useRouter(): RouterApi;
107
- declare function useRoute(): RouteLocation;
108
- declare function useParams(): RouteParams;
109
- declare function useQuery(): RouteQuery;
110
- declare function resolveHref(to: RouteTarget): string;
111
- declare function isActiveHref(to: RouteTarget, options?: MatchOptions): boolean;
112
- declare const Outlet: OlovaComponent;
113
- declare const Router: OlovaComponent;
114
- declare const BrowserRouter: OlovaComponent;
115
- declare const HashRouter: OlovaComponent;
116
-
117
- export { BrowserRouter, HashRouter, _default as Link, type MatchOptions, type NavigateOptions, Outlet, type RouteDefinition, type RouteGuardContext, type RouteLocation, type RouteMatchInfo, type RouteObject, type RouteParams, type RouteQuery, type RouteQueryInput, type RouteTarget, type RouterMode, type RouterProps, type RouterRoutes, Router as default, isActiveHref, link, matchPath, navigate, resolveHref, useParams, useQuery, useRoute, useRouter };
1
+ import 'olova/runtime';
2
+ export { Breadcrumb, B as BrowserRouter, G as GuardCondition, H as HashRouter, I as InterceptConfig, l as InterceptRule, _ as Link, m as MatchOptions, M as Middleware, f as MiddlewareChain, N as NavigateOptions, O as Outlet, R as RouteDefinition, n as RouteGuardContext, o as RouteGuardResult, p as RouteLocation, q as RouteMatchInfo, r as RouteObject, s as RouteParams, t as RouteQuery, u as RouteQueryInput, v as RouteTarget, w as RouterMode, x as RouterProps, y as RouterRoutes, z as applyMetadata, A as buildDynamicPath, C as captureError, D as clearError, E as clearInterceptRules, F as clearMetadataCache, J as clearPrefetchCache, K as clearRouteGroups, L as clearSearchParamsCache, P as conditionalSlot, g as createAnalyticsMiddleware, h as createAuthMiddleware, c as createCompositeGuard, a as createConditionalGuard, b as createDebounceGuard, i as createMiddlewareChain, Q as createParallelRoutes, d as createParamGuard, e as createQueryGuard, j as createRoleMiddleware, S as createRouteGroup, k as createScrollMiddleware, T as default, U as findInterceptor, generateBreadcrumbs, generateBreadcrumbsFromMatches, V as getAllInterceptRules, W as getAllRouteGroups, X as getError, Y as getErrorBoundaryState, Z as getInterceptRule, $ as getRouteGroup, a0 as getRouteMetadata, a1 as hasError, a2 as isActiveHref, a3 as isPrefetched, a4 as link, a5 as matchDynamicRoute, a6 as matchPath, a7 as mergeRouteGroups, a8 as navigate, a9 as parseRoutePattern, aa as prefetchRoute, ab as registerInterceptRule, ac as registerRouteMetadata, ad as removeInterceptRule, ae as removeRouteGroup, af as renderSlot, ag as resetTransition, ah as resolveHref, ai as startTransition, aj as useHash, ak as useParams, al as usePathname, am as useQuery, an as useRoute, ao as useRouter, ap as useSearchParams, aq as useSlot, ar as useTransition } from './breadcrumbs.js';
3
+ export { HistoryEntry, RouterHistory, createRouterHistory } from './history.js';
4
+ export { LazyComponentLoader, lazyComponent, lazyComponentWithFallback } from './lazy.js';