sibujs 1.2.0 → 1.4.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/README.md +29 -25
- package/dist/browser.cjs +804 -2
- package/dist/browser.d.cts +591 -1
- package/dist/browser.d.ts +591 -1
- package/dist/browser.js +50 -8
- package/dist/build.cjs +655 -237
- package/dist/build.js +15 -93
- package/dist/cdn.global.js +188 -7
- package/dist/chunk-2BYQDGN3.js +742 -0
- package/dist/chunk-32DY64NT.js +282 -0
- package/dist/chunk-3AIRKM3B.js +1263 -0
- package/dist/chunk-3X2YG6YM.js +505 -0
- package/dist/chunk-5X6PP2UK.js +28 -0
- package/dist/chunk-77L6NL3X.js +1097 -0
- package/dist/chunk-BGN5ZMP4.js +26 -0
- package/dist/chunk-BTU3TJDS.js +365 -0
- package/dist/chunk-CHF5OHIA.js +61 -0
- package/dist/chunk-CMBFNA7L.js +27 -0
- package/dist/chunk-CNZ35WI2.js +178 -0
- package/dist/chunk-DAHRH4ON.js +331 -0
- package/dist/chunk-EBGIRKQY.js +616 -0
- package/dist/chunk-EUZND3CB.js +27 -0
- package/dist/chunk-F3FA4F32.js +292 -0
- package/dist/chunk-JAKHTMQU.js +1000 -0
- package/dist/chunk-JCI5M6U6.js +956 -0
- package/dist/chunk-KQPDEVVS.js +398 -0
- package/dist/chunk-M4NLBH4I.js +725 -0
- package/dist/chunk-NEKUBFPT.js +60 -0
- package/dist/chunk-NYVAC6P5.js +37 -0
- package/dist/chunk-PTQJDMRT.js +146 -0
- package/dist/chunk-QWZG56ET.js +2744 -0
- package/dist/chunk-TSOKIX5Z.js +654 -0
- package/dist/chunk-UHNL42EF.js +2730 -0
- package/dist/chunk-VRW3FULF.js +725 -0
- package/dist/chunk-WZSPOOER.js +84 -0
- package/dist/chunk-YT6HQ6AM.js +14 -0
- package/dist/chunk-ZD6OAMTH.js +277 -0
- package/dist/chunk-ZWKZCBO6.js +317 -0
- package/dist/contracts-DDrwxvJ-.d.cts +245 -0
- package/dist/contracts-DDrwxvJ-.d.ts +245 -0
- package/dist/contracts-xo5ckdRP.d.cts +240 -0
- package/dist/contracts-xo5ckdRP.d.ts +240 -0
- package/dist/data.cjs +35 -2
- package/dist/data.d.cts +7 -0
- package/dist/data.d.ts +7 -0
- package/dist/data.js +9 -8
- package/dist/devtools.cjs +122 -0
- package/dist/devtools.d.cts +69 -461
- package/dist/devtools.d.ts +69 -461
- package/dist/devtools.js +127 -6
- package/dist/ecosystem.cjs +23 -6
- package/dist/ecosystem.d.cts +1 -1
- package/dist/ecosystem.d.ts +1 -1
- package/dist/ecosystem.js +10 -9
- package/dist/extras.cjs +1208 -88
- package/dist/extras.d.cts +6 -6
- package/dist/extras.d.ts +6 -6
- package/dist/extras.js +70 -33
- package/dist/index.cjs +663 -158
- package/dist/index.d.cts +398 -40
- package/dist/index.d.ts +398 -40
- package/dist/index.js +39 -21
- package/dist/introspect-BumjnBKr.d.cts +477 -0
- package/dist/introspect-CZrlcaYy.d.ts +477 -0
- package/dist/introspect-Cb0zgpi2.d.cts +477 -0
- package/dist/introspect-Y2xNXGSf.d.ts +477 -0
- package/dist/motion.js +4 -4
- package/dist/patterns.cjs +51 -24
- package/dist/patterns.d.cts +19 -57
- package/dist/patterns.d.ts +19 -57
- package/dist/patterns.js +8 -16
- package/dist/performance.js +4 -4
- package/dist/plugins.cjs +429 -82
- package/dist/plugins.d.cts +27 -4
- package/dist/plugins.d.ts +27 -4
- package/dist/plugins.js +156 -37
- package/dist/ssr-4PBXAOO3.js +40 -0
- package/dist/ssr-Do_SiVoL.d.cts +201 -0
- package/dist/ssr-Do_SiVoL.d.ts +201 -0
- package/dist/ssr.cjs +312 -60
- package/dist/ssr.d.cts +10 -1
- package/dist/ssr.d.ts +10 -1
- package/dist/ssr.js +13 -10
- package/dist/tagFactory-DaJ0YWX6.d.cts +47 -0
- package/dist/tagFactory-DaJ0YWX6.d.ts +47 -0
- package/dist/testing.cjs +233 -2
- package/dist/testing.d.cts +42 -1
- package/dist/testing.d.ts +42 -1
- package/dist/testing.js +129 -2
- package/dist/ui.cjs +374 -8
- package/dist/ui.d.cts +252 -2
- package/dist/ui.d.ts +252 -2
- package/dist/ui.js +329 -11
- package/dist/widgets.js +7 -7
- package/package.json +1 -1
package/dist/plugins.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as TrustedHTML } from './ssr-
|
|
1
|
+
import { T as TrustedHTML } from './ssr-Do_SiVoL.cjs';
|
|
2
2
|
export { P as PluginContext, S as SibuPlugin, c as createPlugin, i as inject, p as plugin, r as resetPlugins, t as triggerPluginError, a as triggerPluginMount, b as triggerPluginUnmount } from './plugin-Bek4RhJY.cjs';
|
|
3
3
|
export { M as Migration, S as SemVer, V as VERSION, b as bundlerMetadata, c as checkCompatibility, a as compareSemVer, d as createBootSequence, e as createBundle, f as createMigrationRunner, g as createModuleRegistry, h as createSSRCache, i as createTestHarness, j as deferNonCritical, k as env, l as healthCheck, m as lazyModule, p as packageInfo, n as parseSemVer, o as preloadCritical, q as prerenderRoutes, s as satisfies } from './startup-0Qv6aosO.cjs';
|
|
4
4
|
|
|
@@ -74,7 +74,19 @@ interface AsyncRoute extends RouteBase {
|
|
|
74
74
|
interface RedirectRoute extends RouteBase {
|
|
75
75
|
readonly redirect: string | ((to: RouteContext) => string);
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
/**
|
|
78
|
+
* A route whose component is loaded on first visit via a dynamic
|
|
79
|
+
* `import()`. This is the ergonomic shorthand for
|
|
80
|
+
* `{ component: lazy(() => import("./Page")) }`.
|
|
81
|
+
*
|
|
82
|
+
* The loader must return a module with a `default` Component export.
|
|
83
|
+
*/
|
|
84
|
+
interface LazyRoute extends RouteBase {
|
|
85
|
+
readonly lazy: () => Promise<{
|
|
86
|
+
default: Component;
|
|
87
|
+
}>;
|
|
88
|
+
}
|
|
89
|
+
type RouteDef = ComponentRoute | AsyncRoute | RedirectRoute | LazyRoute;
|
|
78
90
|
interface RouterOptions {
|
|
79
91
|
readonly mode?: "history" | "hash";
|
|
80
92
|
readonly base?: string;
|
|
@@ -381,6 +393,11 @@ declare function renderRouteToString(url: string, routes: SSRRouteDef[], _option
|
|
|
381
393
|
/**
|
|
382
394
|
* Generate the full HTML document for a route including serialized state.
|
|
383
395
|
* Uses renderToDocument pattern with embedded route state.
|
|
396
|
+
*
|
|
397
|
+
* Security: meta/link attribute names are validated against
|
|
398
|
+
* `SAFE_ATTR_NAME`, URL attributes are routed through `sanitizeUrl`,
|
|
399
|
+
* `title` is HTML-escaped, and the embedded state script escapes
|
|
400
|
+
* `U+2028` / `U+2029` plus the usual `<`/`>`/`&` trio.
|
|
384
401
|
*/
|
|
385
402
|
declare function renderRouteToDocument(url: string, routes: SSRRouteDef[], options?: {
|
|
386
403
|
title?: string;
|
|
@@ -388,12 +405,17 @@ declare function renderRouteToDocument(url: string, routes: SSRRouteDef[], optio
|
|
|
388
405
|
links?: Record<string, string>[];
|
|
389
406
|
scripts?: string[];
|
|
390
407
|
headExtra?: TrustedHTML;
|
|
408
|
+
nonce?: string;
|
|
391
409
|
}): string;
|
|
392
410
|
/**
|
|
393
411
|
* Serialize route state for embedding in HTML.
|
|
394
412
|
* Uses a specific key (__SIBU_ROUTE_STATE__) distinct from the generic SSR data key.
|
|
413
|
+
*
|
|
414
|
+
* Security: escapes `<`/`>`/`&` and the ES line-terminator pairs
|
|
415
|
+
* `U+2028` / `U+2029`. Supports an optional `nonce` attribute for
|
|
416
|
+
* strict-CSP compatibility.
|
|
395
417
|
*/
|
|
396
|
-
declare function serializeRouteState(state: SSRRouteState): string;
|
|
418
|
+
declare function serializeRouteState(state: SSRRouteState, nonce?: string): string;
|
|
397
419
|
/**
|
|
398
420
|
* Deserialize route state on the client from server-embedded data.
|
|
399
421
|
* Reads from window.__SIBU_ROUTE_STATE__.
|
|
@@ -430,7 +452,8 @@ declare function createSSRRouter(routes: SSRRouteDef[]): {
|
|
|
430
452
|
links?: Record<string, string>[];
|
|
431
453
|
scripts?: string[];
|
|
432
454
|
headExtra?: TrustedHTML;
|
|
455
|
+
nonce?: string;
|
|
433
456
|
}) => string;
|
|
434
457
|
};
|
|
435
458
|
|
|
436
|
-
export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type NavigationFailure, type NavigationGuard, type NavigationNext, type NavigationResult, type NavigationTarget, Outlet, type Params, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t };
|
|
459
|
+
export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type LazyRoute, type NavigationFailure, type NavigationGuard, type NavigationNext, type NavigationResult, type NavigationTarget, Outlet, type Params, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t };
|
package/dist/plugins.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as TrustedHTML } from './ssr-
|
|
1
|
+
import { T as TrustedHTML } from './ssr-Do_SiVoL.js';
|
|
2
2
|
export { P as PluginContext, S as SibuPlugin, c as createPlugin, i as inject, p as plugin, r as resetPlugins, t as triggerPluginError, a as triggerPluginMount, b as triggerPluginUnmount } from './plugin-Bek4RhJY.js';
|
|
3
3
|
export { M as Migration, S as SemVer, V as VERSION, b as bundlerMetadata, c as checkCompatibility, a as compareSemVer, d as createBootSequence, e as createBundle, f as createMigrationRunner, g as createModuleRegistry, h as createSSRCache, i as createTestHarness, j as deferNonCritical, k as env, l as healthCheck, m as lazyModule, p as packageInfo, n as parseSemVer, o as preloadCritical, q as prerenderRoutes, s as satisfies } from './startup-0Qv6aosO.js';
|
|
4
4
|
|
|
@@ -74,7 +74,19 @@ interface AsyncRoute extends RouteBase {
|
|
|
74
74
|
interface RedirectRoute extends RouteBase {
|
|
75
75
|
readonly redirect: string | ((to: RouteContext) => string);
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
/**
|
|
78
|
+
* A route whose component is loaded on first visit via a dynamic
|
|
79
|
+
* `import()`. This is the ergonomic shorthand for
|
|
80
|
+
* `{ component: lazy(() => import("./Page")) }`.
|
|
81
|
+
*
|
|
82
|
+
* The loader must return a module with a `default` Component export.
|
|
83
|
+
*/
|
|
84
|
+
interface LazyRoute extends RouteBase {
|
|
85
|
+
readonly lazy: () => Promise<{
|
|
86
|
+
default: Component;
|
|
87
|
+
}>;
|
|
88
|
+
}
|
|
89
|
+
type RouteDef = ComponentRoute | AsyncRoute | RedirectRoute | LazyRoute;
|
|
78
90
|
interface RouterOptions {
|
|
79
91
|
readonly mode?: "history" | "hash";
|
|
80
92
|
readonly base?: string;
|
|
@@ -381,6 +393,11 @@ declare function renderRouteToString(url: string, routes: SSRRouteDef[], _option
|
|
|
381
393
|
/**
|
|
382
394
|
* Generate the full HTML document for a route including serialized state.
|
|
383
395
|
* Uses renderToDocument pattern with embedded route state.
|
|
396
|
+
*
|
|
397
|
+
* Security: meta/link attribute names are validated against
|
|
398
|
+
* `SAFE_ATTR_NAME`, URL attributes are routed through `sanitizeUrl`,
|
|
399
|
+
* `title` is HTML-escaped, and the embedded state script escapes
|
|
400
|
+
* `U+2028` / `U+2029` plus the usual `<`/`>`/`&` trio.
|
|
384
401
|
*/
|
|
385
402
|
declare function renderRouteToDocument(url: string, routes: SSRRouteDef[], options?: {
|
|
386
403
|
title?: string;
|
|
@@ -388,12 +405,17 @@ declare function renderRouteToDocument(url: string, routes: SSRRouteDef[], optio
|
|
|
388
405
|
links?: Record<string, string>[];
|
|
389
406
|
scripts?: string[];
|
|
390
407
|
headExtra?: TrustedHTML;
|
|
408
|
+
nonce?: string;
|
|
391
409
|
}): string;
|
|
392
410
|
/**
|
|
393
411
|
* Serialize route state for embedding in HTML.
|
|
394
412
|
* Uses a specific key (__SIBU_ROUTE_STATE__) distinct from the generic SSR data key.
|
|
413
|
+
*
|
|
414
|
+
* Security: escapes `<`/`>`/`&` and the ES line-terminator pairs
|
|
415
|
+
* `U+2028` / `U+2029`. Supports an optional `nonce` attribute for
|
|
416
|
+
* strict-CSP compatibility.
|
|
395
417
|
*/
|
|
396
|
-
declare function serializeRouteState(state: SSRRouteState): string;
|
|
418
|
+
declare function serializeRouteState(state: SSRRouteState, nonce?: string): string;
|
|
397
419
|
/**
|
|
398
420
|
* Deserialize route state on the client from server-embedded data.
|
|
399
421
|
* Reads from window.__SIBU_ROUTE_STATE__.
|
|
@@ -430,7 +452,8 @@ declare function createSSRRouter(routes: SSRRouteDef[]): {
|
|
|
430
452
|
links?: Record<string, string>[];
|
|
431
453
|
scripts?: string[];
|
|
432
454
|
headExtra?: TrustedHTML;
|
|
455
|
+
nonce?: string;
|
|
433
456
|
}) => string;
|
|
434
457
|
};
|
|
435
458
|
|
|
436
|
-
export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type NavigationFailure, type NavigationGuard, type NavigationNext, type NavigationResult, type NavigationTarget, Outlet, type Params, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t };
|
|
459
|
+
export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type LazyRoute, type NavigationFailure, type NavigationGuard, type NavigationNext, type NavigationResult, type NavigationTarget, Outlet, type Params, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t };
|
package/dist/plugins.js
CHANGED
|
@@ -18,10 +18,11 @@ import {
|
|
|
18
18
|
preloadCritical,
|
|
19
19
|
prerenderRoutes,
|
|
20
20
|
satisfies
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-M4NLBH4I.js";
|
|
22
22
|
import {
|
|
23
|
+
escapeScriptJson,
|
|
23
24
|
renderToString
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-3X2YG6YM.js";
|
|
25
26
|
import {
|
|
26
27
|
createPlugin,
|
|
27
28
|
inject,
|
|
@@ -33,22 +34,26 @@ import {
|
|
|
33
34
|
} from "./chunk-K5ZUMYVS.js";
|
|
34
35
|
import {
|
|
35
36
|
span
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-32DY64NT.js";
|
|
38
|
+
import "./chunk-F3FA4F32.js";
|
|
37
39
|
import {
|
|
38
40
|
dispose,
|
|
39
41
|
registerDisposer
|
|
40
|
-
} from "./chunk-
|
|
41
|
-
import
|
|
42
|
+
} from "./chunk-PTQJDMRT.js";
|
|
43
|
+
import {
|
|
44
|
+
sanitizeUrl
|
|
45
|
+
} from "./chunk-CMBFNA7L.js";
|
|
42
46
|
import {
|
|
43
47
|
effect
|
|
44
|
-
} from "./chunk-
|
|
45
|
-
import "./chunk-
|
|
48
|
+
} from "./chunk-CHF5OHIA.js";
|
|
49
|
+
import "./chunk-EUZND3CB.js";
|
|
50
|
+
import {
|
|
51
|
+
signal
|
|
52
|
+
} from "./chunk-WZSPOOER.js";
|
|
46
53
|
import {
|
|
47
|
-
signal,
|
|
48
54
|
track
|
|
49
|
-
} from "./chunk-
|
|
50
|
-
import "./chunk-
|
|
51
|
-
import "./chunk-MLKGABMK.js";
|
|
55
|
+
} from "./chunk-ZD6OAMTH.js";
|
|
56
|
+
import "./chunk-5X6PP2UK.js";
|
|
52
57
|
|
|
53
58
|
// src/plugins/i18n.ts
|
|
54
59
|
var [currentLocale, setLocaleInternal] = signal("en");
|
|
@@ -81,6 +86,10 @@ function getAvailableLocales() {
|
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
// src/plugins/router.ts
|
|
89
|
+
function isSafeNavigationTarget(path) {
|
|
90
|
+
if (path === "") return true;
|
|
91
|
+
return sanitizeUrl(path) !== "";
|
|
92
|
+
}
|
|
84
93
|
var LRUCache = class {
|
|
85
94
|
constructor(maxSize = 100) {
|
|
86
95
|
this.cache = /* @__PURE__ */ new Map();
|
|
@@ -566,6 +575,11 @@ var _SibuRouter = class _SibuRouter {
|
|
|
566
575
|
try {
|
|
567
576
|
await this.navigator.navigate(async (signal2) => {
|
|
568
577
|
const targetPath = this.resolvePath(to);
|
|
578
|
+
if (!isSafeNavigationTarget(targetPath)) {
|
|
579
|
+
const from2 = this.currentRouteGetter();
|
|
580
|
+
const toContext2 = this.createRouteContext(targetPath);
|
|
581
|
+
throw new NavigationFailureError("aborted", from2, toContext2);
|
|
582
|
+
}
|
|
569
583
|
const from = this.currentRouteGetter();
|
|
570
584
|
const toContext = this.createRouteContext(targetPath);
|
|
571
585
|
if (this.isSameRoute(from, toContext)) {
|
|
@@ -595,6 +609,9 @@ var _SibuRouter = class _SibuRouter {
|
|
|
595
609
|
const beforeEachResult = await this.guards.runBeforeEach(to, from, signal2);
|
|
596
610
|
if (beforeEachResult !== true) {
|
|
597
611
|
if (typeof beforeEachResult === "string") {
|
|
612
|
+
if (!isSafeNavigationTarget(beforeEachResult)) {
|
|
613
|
+
throw new NavigationFailureError("aborted", from, to);
|
|
614
|
+
}
|
|
598
615
|
return this.performNavigation(this.createRouteContext(beforeEachResult), from, options, signal2, depth + 1);
|
|
599
616
|
}
|
|
600
617
|
throw new NavigationFailureError("aborted", from, to);
|
|
@@ -610,6 +627,9 @@ var _SibuRouter = class _SibuRouter {
|
|
|
610
627
|
const result = await guard(to, from);
|
|
611
628
|
if (result !== true) {
|
|
612
629
|
if (typeof result === "string") {
|
|
630
|
+
if (!isSafeNavigationTarget(result)) {
|
|
631
|
+
throw new NavigationFailureError("aborted", from, to);
|
|
632
|
+
}
|
|
613
633
|
return this.performNavigation(this.createRouteContext(result), from, options, signal2, depth + 1);
|
|
614
634
|
}
|
|
615
635
|
throw new NavigationFailureError("aborted", from, to);
|
|
@@ -624,12 +644,18 @@ var _SibuRouter = class _SibuRouter {
|
|
|
624
644
|
`[SibuJS Router] Redirect to absolute URL "${redirectPath}" detected. Use relative paths for safer redirects.`
|
|
625
645
|
);
|
|
626
646
|
}
|
|
647
|
+
if (typeof redirectPath === "string" && !isSafeNavigationTarget(redirectPath)) {
|
|
648
|
+
throw new NavigationFailureError("aborted", from, to);
|
|
649
|
+
}
|
|
627
650
|
return this.performNavigation(this.createRouteContext(redirectPath), from, options, signal2, depth + 1);
|
|
628
651
|
}
|
|
629
652
|
}
|
|
630
653
|
const beforeResolveResult = await this.guards.runBeforeResolve(to, from, signal2);
|
|
631
654
|
if (beforeResolveResult !== true) {
|
|
632
655
|
if (typeof beforeResolveResult === "string") {
|
|
656
|
+
if (!isSafeNavigationTarget(beforeResolveResult)) {
|
|
657
|
+
throw new NavigationFailureError("aborted", from, to);
|
|
658
|
+
}
|
|
633
659
|
return this.performNavigation(this.createRouteContext(beforeResolveResult), from, options, signal2, depth + 1);
|
|
634
660
|
}
|
|
635
661
|
throw new NavigationFailureError("aborted", from, to);
|
|
@@ -789,13 +815,31 @@ var NavigationFailureError = class extends Error {
|
|
|
789
815
|
}
|
|
790
816
|
};
|
|
791
817
|
var globalRouter = null;
|
|
818
|
+
function normalizeRoutes(routes) {
|
|
819
|
+
return routes.map((route2) => {
|
|
820
|
+
const normalizedChildren = route2.children && route2.children.length > 0 ? normalizeRoutes(route2.children) : route2.children;
|
|
821
|
+
if ("lazy" in route2 && typeof route2.lazy === "function") {
|
|
822
|
+
const { lazy: importFn, ...rest } = route2;
|
|
823
|
+
const asyncRoute = {
|
|
824
|
+
...rest,
|
|
825
|
+
component: lazy(importFn),
|
|
826
|
+
children: normalizedChildren
|
|
827
|
+
};
|
|
828
|
+
return asyncRoute;
|
|
829
|
+
}
|
|
830
|
+
if (normalizedChildren !== route2.children) {
|
|
831
|
+
return { ...route2, children: normalizedChildren };
|
|
832
|
+
}
|
|
833
|
+
return route2;
|
|
834
|
+
});
|
|
835
|
+
}
|
|
792
836
|
function createRouter(routesOrOptions, options = {}) {
|
|
793
837
|
if (globalRouter) {
|
|
794
838
|
globalRouter.destroy();
|
|
795
839
|
}
|
|
796
840
|
let routes;
|
|
797
841
|
if (Array.isArray(routesOrOptions)) {
|
|
798
|
-
routes = routesOrOptions;
|
|
842
|
+
routes = normalizeRoutes(routesOrOptions);
|
|
799
843
|
} else {
|
|
800
844
|
options = routesOrOptions;
|
|
801
845
|
routes = [];
|
|
@@ -805,7 +849,7 @@ function createRouter(routesOrOptions, options = {}) {
|
|
|
805
849
|
}
|
|
806
850
|
function setRoutes(routes) {
|
|
807
851
|
if (!globalRouter) throw new Error("Router not initialized. Call createRouter() first.");
|
|
808
|
-
globalRouter.updateRoutes(routes);
|
|
852
|
+
globalRouter.updateRoutes(normalizeRoutes(routes));
|
|
809
853
|
}
|
|
810
854
|
function route() {
|
|
811
855
|
if (!globalRouter) throw new Error("Router not initialized. Call createRouter() first.");
|
|
@@ -1385,6 +1429,20 @@ function createMemoryRouter(routes, _initialPath = "/") {
|
|
|
1385
1429
|
}
|
|
1386
1430
|
|
|
1387
1431
|
// src/plugins/routerSSR.ts
|
|
1432
|
+
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1433
|
+
function isForbiddenKey(key) {
|
|
1434
|
+
return FORBIDDEN_KEYS.has(key);
|
|
1435
|
+
}
|
|
1436
|
+
function safeDecode(raw) {
|
|
1437
|
+
try {
|
|
1438
|
+
return decodeURIComponent(raw);
|
|
1439
|
+
} catch {
|
|
1440
|
+
return raw;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
function nullObject() {
|
|
1444
|
+
return /* @__PURE__ */ Object.create(null);
|
|
1445
|
+
}
|
|
1388
1446
|
function parseURL(url) {
|
|
1389
1447
|
let remaining = url;
|
|
1390
1448
|
let hash = "";
|
|
@@ -1400,19 +1458,23 @@ function parseURL(url) {
|
|
|
1400
1458
|
remaining = remaining.slice(0, queryIndex);
|
|
1401
1459
|
}
|
|
1402
1460
|
const path = remaining || "/";
|
|
1403
|
-
const query =
|
|
1461
|
+
const query = nullObject();
|
|
1404
1462
|
if (queryString) {
|
|
1405
1463
|
const pairs = queryString.split("&");
|
|
1406
1464
|
for (const pair of pairs) {
|
|
1407
1465
|
if (!pair) continue;
|
|
1408
1466
|
const eqIndex = pair.indexOf("=");
|
|
1467
|
+
let key;
|
|
1468
|
+
let value;
|
|
1409
1469
|
if (eqIndex === -1) {
|
|
1410
|
-
|
|
1470
|
+
key = safeDecode(pair);
|
|
1471
|
+
value = "";
|
|
1411
1472
|
} else {
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
query[key] = value;
|
|
1473
|
+
key = safeDecode(pair.slice(0, eqIndex));
|
|
1474
|
+
value = safeDecode(pair.slice(eqIndex + 1));
|
|
1415
1475
|
}
|
|
1476
|
+
if (isForbiddenKey(key)) continue;
|
|
1477
|
+
query[key] = value;
|
|
1416
1478
|
}
|
|
1417
1479
|
}
|
|
1418
1480
|
return { path, query, hash };
|
|
@@ -1470,10 +1532,12 @@ function matchRoute(path, routes, parentPath = "", parentChain = []) {
|
|
|
1470
1532
|
const compiled = compilePattern(fullPath);
|
|
1471
1533
|
const match = path.match(compiled.regex);
|
|
1472
1534
|
if (match) {
|
|
1473
|
-
const params =
|
|
1535
|
+
const params = nullObject();
|
|
1474
1536
|
for (let i = 0; i < compiled.keys.length; i++) {
|
|
1537
|
+
const key = compiled.keys[i];
|
|
1538
|
+
if (isForbiddenKey(key)) continue;
|
|
1475
1539
|
if (match[i + 1] !== void 0) {
|
|
1476
|
-
params[
|
|
1540
|
+
params[key] = safeDecode(match[i + 1]);
|
|
1477
1541
|
}
|
|
1478
1542
|
}
|
|
1479
1543
|
return {
|
|
@@ -1508,7 +1572,7 @@ function resolveServerRouteInternal(url, routes, depth) {
|
|
|
1508
1572
|
return {
|
|
1509
1573
|
route: {
|
|
1510
1574
|
path: normalizedPath,
|
|
1511
|
-
params:
|
|
1575
|
+
params: nullObject(),
|
|
1512
1576
|
query,
|
|
1513
1577
|
hash,
|
|
1514
1578
|
meta: {}
|
|
@@ -1568,20 +1632,26 @@ function renderRouteToString(url, routes, _options) {
|
|
|
1568
1632
|
function renderRouteToDocument(url, routes, options) {
|
|
1569
1633
|
const { html, state } = renderRouteToString(url, routes, options);
|
|
1570
1634
|
const opts = options || {};
|
|
1571
|
-
const metaTags = (opts.meta || []).map(
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1635
|
+
const metaTags = (opts.meta || []).map((attrs) => {
|
|
1636
|
+
const pairs = buildSafeAttrString(attrs);
|
|
1637
|
+
return pairs ? `<meta ${pairs} />` : "";
|
|
1638
|
+
}).filter(Boolean).join("\n ");
|
|
1639
|
+
const linkTags = (opts.links || []).map((attrs) => {
|
|
1640
|
+
const pairs = buildSafeAttrString(attrs);
|
|
1641
|
+
return pairs ? `<link ${pairs} />` : "";
|
|
1642
|
+
}).filter(Boolean).join("\n ");
|
|
1643
|
+
const scriptTags = (opts.scripts || []).map((src) => {
|
|
1644
|
+
const safe = sanitizeUrlLocal(String(src));
|
|
1645
|
+
if (!safe) return "";
|
|
1646
|
+
return `<script src="${escapeAttrLocal(safe)}"></script>`;
|
|
1647
|
+
}).filter(Boolean).join("\n ");
|
|
1648
|
+
const stateScript = serializeRouteState(state, opts.nonce);
|
|
1579
1649
|
return `<!DOCTYPE html>
|
|
1580
1650
|
<html>
|
|
1581
1651
|
<head>
|
|
1582
1652
|
<meta charset="UTF-8" />
|
|
1583
1653
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1584
|
-
${opts.title ? `<title>${
|
|
1654
|
+
${opts.title ? `<title>${escapeHtmlLocal(opts.title)}</title>` : ""}
|
|
1585
1655
|
${metaTags}
|
|
1586
1656
|
${linkTags}
|
|
1587
1657
|
${opts.headExtra || ""}
|
|
@@ -1593,9 +1663,10 @@ function renderRouteToDocument(url, routes, options) {
|
|
|
1593
1663
|
</body>
|
|
1594
1664
|
</html>`;
|
|
1595
1665
|
}
|
|
1596
|
-
function serializeRouteState(state) {
|
|
1597
|
-
const json = JSON.stringify(state)
|
|
1598
|
-
|
|
1666
|
+
function serializeRouteState(state, nonce) {
|
|
1667
|
+
const json = escapeScriptJson(JSON.stringify(state));
|
|
1668
|
+
const nonceAttr = nonce ? ` nonce="${escapeAttrLocal(nonce)}"` : "";
|
|
1669
|
+
return `<script${nonceAttr}>window.${SSR_ROUTE_STATE_KEY}=${json}</script>`;
|
|
1599
1670
|
}
|
|
1600
1671
|
function deserializeRouteState() {
|
|
1601
1672
|
if (typeof window === "undefined") return void 0;
|
|
@@ -1612,7 +1683,7 @@ function hydrateRouter(routes, options) {
|
|
|
1612
1683
|
if (container && serverState.path) {
|
|
1613
1684
|
const resolved = resolveServerRoute(serverState.path, routes);
|
|
1614
1685
|
if (resolved.component) {
|
|
1615
|
-
import("./ssr-
|
|
1686
|
+
import("./ssr-4PBXAOO3.js").then(({ hydrate }) => {
|
|
1616
1687
|
if (resolved.component) {
|
|
1617
1688
|
hydrate(resolved.component, container);
|
|
1618
1689
|
}
|
|
@@ -1633,11 +1704,59 @@ function createSSRRouter(routes) {
|
|
|
1633
1704
|
}
|
|
1634
1705
|
};
|
|
1635
1706
|
}
|
|
1636
|
-
|
|
1707
|
+
var SAFE_ATTR_NAME = /^[A-Za-z_:][-A-Za-z0-9_.:]*$/;
|
|
1708
|
+
function isSafeAttrName(name) {
|
|
1709
|
+
return SAFE_ATTR_NAME.test(name);
|
|
1710
|
+
}
|
|
1711
|
+
function isEventHandlerAttr(name) {
|
|
1712
|
+
if (name.length < 3) return false;
|
|
1713
|
+
const lower = name.toLowerCase();
|
|
1714
|
+
return lower[0] === "o" && lower[1] === "n" && lower.charCodeAt(2) >= 97 && lower.charCodeAt(2) <= 122;
|
|
1715
|
+
}
|
|
1716
|
+
var URL_ATTRS = /* @__PURE__ */ new Set([
|
|
1717
|
+
"href",
|
|
1718
|
+
"src",
|
|
1719
|
+
"action",
|
|
1720
|
+
"formaction",
|
|
1721
|
+
"cite",
|
|
1722
|
+
"poster",
|
|
1723
|
+
"background",
|
|
1724
|
+
"srcset",
|
|
1725
|
+
"ping",
|
|
1726
|
+
"manifest",
|
|
1727
|
+
"data",
|
|
1728
|
+
"xlink:href"
|
|
1729
|
+
]);
|
|
1730
|
+
function sanitizeUrlLocal(url) {
|
|
1731
|
+
const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
|
|
1732
|
+
if (!trimmed) return "";
|
|
1733
|
+
const lower = trimmed.toLowerCase();
|
|
1734
|
+
if (lower.startsWith("javascript:") || lower.startsWith("data:") || lower.startsWith("vbscript:") || lower.startsWith("blob:")) {
|
|
1735
|
+
return "";
|
|
1736
|
+
}
|
|
1737
|
+
return trimmed;
|
|
1738
|
+
}
|
|
1739
|
+
function buildSafeAttrString(attrs) {
|
|
1740
|
+
const out = [];
|
|
1741
|
+
for (const rawKey of Object.keys(attrs)) {
|
|
1742
|
+
if (!Object.hasOwn(attrs, rawKey)) continue;
|
|
1743
|
+
if (!isSafeAttrName(rawKey)) continue;
|
|
1744
|
+
if (isEventHandlerAttr(rawKey)) continue;
|
|
1745
|
+
const lowerKey = rawKey.toLowerCase();
|
|
1746
|
+
let value = String(attrs[rawKey]);
|
|
1747
|
+
if (URL_ATTRS.has(lowerKey)) {
|
|
1748
|
+
value = sanitizeUrlLocal(value);
|
|
1749
|
+
if (!value) continue;
|
|
1750
|
+
}
|
|
1751
|
+
out.push(`${rawKey}="${escapeAttrLocal(value)}"`);
|
|
1752
|
+
}
|
|
1753
|
+
return out.join(" ");
|
|
1754
|
+
}
|
|
1755
|
+
function escapeHtmlLocal(str) {
|
|
1637
1756
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1638
1757
|
}
|
|
1639
|
-
function
|
|
1640
|
-
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
1758
|
+
function escapeAttrLocal(str) {
|
|
1759
|
+
return str.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1641
1760
|
}
|
|
1642
1761
|
export {
|
|
1643
1762
|
KeepAliveRoute,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collectStream,
|
|
3
|
+
deserializeState,
|
|
4
|
+
escapeScriptJson,
|
|
5
|
+
hydrate,
|
|
6
|
+
hydrateIslands,
|
|
7
|
+
hydrateProgressively,
|
|
8
|
+
island,
|
|
9
|
+
renderToDocument,
|
|
10
|
+
renderToReadableStream,
|
|
11
|
+
renderToStream,
|
|
12
|
+
renderToString,
|
|
13
|
+
renderToSuspenseStream,
|
|
14
|
+
resetSSRState,
|
|
15
|
+
serializeState,
|
|
16
|
+
ssrSuspense,
|
|
17
|
+
suspenseSwapScript,
|
|
18
|
+
trustHTML
|
|
19
|
+
} from "./chunk-3X2YG6YM.js";
|
|
20
|
+
import "./chunk-CMBFNA7L.js";
|
|
21
|
+
import "./chunk-5X6PP2UK.js";
|
|
22
|
+
export {
|
|
23
|
+
collectStream,
|
|
24
|
+
deserializeState,
|
|
25
|
+
escapeScriptJson,
|
|
26
|
+
hydrate,
|
|
27
|
+
hydrateIslands,
|
|
28
|
+
hydrateProgressively,
|
|
29
|
+
island,
|
|
30
|
+
renderToDocument,
|
|
31
|
+
renderToReadableStream,
|
|
32
|
+
renderToStream,
|
|
33
|
+
renderToString,
|
|
34
|
+
renderToSuspenseStream,
|
|
35
|
+
resetSSRState,
|
|
36
|
+
serializeState,
|
|
37
|
+
ssrSuspense,
|
|
38
|
+
suspenseSwapScript,
|
|
39
|
+
trustHTML
|
|
40
|
+
};
|