@askrjs/askr 0.0.34 → 0.0.35
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/dist/benchmark.js +2 -2
- package/dist/common/router.d.ts +8 -1
- package/dist/common/router.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/router/index.d.ts +3 -3
- package/dist/router/index.js +2 -2
- package/dist/router/navigate.d.ts.map +1 -1
- package/dist/router/navigate.js +4 -1
- package/dist/router/navigate.js.map +1 -1
- package/dist/router/route.d.ts +11 -2
- package/dist/router/route.d.ts.map +1 -1
- package/dist/router/route.js +271 -81
- package/dist/router/route.js.map +1 -1
- package/dist/runtime/readable.d.ts +1 -1
- package/dist/runtime/readable.d.ts.map +1 -1
- package/dist/runtime/readable.js +2 -1
- package/dist/runtime/readable.js.map +1 -1
- package/package.json +2 -2
package/dist/benchmark.js
CHANGED
|
@@ -10,8 +10,8 @@ import { BenchmarkTable } from "./bench/components/benchmark-table.js";
|
|
|
10
10
|
installRendererBridge();
|
|
11
11
|
const benchmarkMetadata = {
|
|
12
12
|
packageName: "@askrjs/askr",
|
|
13
|
-
packageVersion: "0.0.
|
|
14
|
-
buildLabel: "0.0.
|
|
13
|
+
packageVersion: "0.0.35",
|
|
14
|
+
buildLabel: "0.0.35-local"
|
|
15
15
|
};
|
|
16
16
|
function getBenchmarkMetadata() {
|
|
17
17
|
return { ...benchmarkMetadata };
|
package/dist/common/router.d.ts
CHANGED
|
@@ -73,6 +73,7 @@ interface RouteOptions extends CommonAccessOptions {
|
|
|
73
73
|
title?: string;
|
|
74
74
|
namespace?: string;
|
|
75
75
|
}
|
|
76
|
+
interface PageHelperOptions extends CommonAccessOptions {}
|
|
76
77
|
/**
|
|
77
78
|
* A single parsed segment from a route path.
|
|
78
79
|
*
|
|
@@ -92,6 +93,10 @@ interface LayoutScopeRecord {
|
|
|
92
93
|
children?: unknown;
|
|
93
94
|
}) => unknown;
|
|
94
95
|
}
|
|
96
|
+
/** Resolved page host component as stored in a route record's page chain. */
|
|
97
|
+
interface PageScopeRecord {
|
|
98
|
+
component: RouteComponent;
|
|
99
|
+
}
|
|
95
100
|
interface RegisterRoutesOptions {
|
|
96
101
|
auth?: RouteAuthOptions;
|
|
97
102
|
}
|
|
@@ -132,6 +137,8 @@ interface RouteRecord {
|
|
|
132
137
|
rank: number;
|
|
133
138
|
/** Layout chain from outermost to innermost, applied automatically on render */
|
|
134
139
|
layoutChain: LayoutScopeRecord[];
|
|
140
|
+
/** Page chain from outermost to innermost, composed through Outlet before layouts apply */
|
|
141
|
+
pageChain: PageScopeRecord[];
|
|
135
142
|
/** Route metadata: loader, entries, policies, title, namespace */
|
|
136
143
|
options: RouteOptions;
|
|
137
144
|
/** True when this is the `/*` catch-all fallback route */
|
|
@@ -193,5 +200,5 @@ interface RouteSnapshot {
|
|
|
193
200
|
matches: readonly RouteMatch[];
|
|
194
201
|
}
|
|
195
202
|
//#endregion
|
|
196
|
-
export { AccessDecision, AccessDenyDecision, AccessDenyStatus, AccessRedirectDecision, AccessRedirectStatus, GroupHelperOptions, LayoutScopeRecord, ParsedSegment, RegisterRoutesOptions, ResolvedRoute, Route, RouteAuthMode, RouteAuthOptions, RouteAuthResolver, RouteAuthState, RouteComponent, RouteContext, RouteDefinition, RouteHandler, RouteManifest, RouteMatch, RouteMode, RouteOptions, RoutePolicy, RouteQuery, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot };
|
|
203
|
+
export { AccessDecision, AccessDenyDecision, AccessDenyStatus, AccessRedirectDecision, AccessRedirectStatus, GroupHelperOptions, LayoutScopeRecord, PageHelperOptions, PageScopeRecord, ParsedSegment, RegisterRoutesOptions, ResolvedRoute, Route, RouteAuthMode, RouteAuthOptions, RouteAuthResolver, RouteAuthState, RouteComponent, RouteContext, RouteDefinition, RouteHandler, RouteManifest, RouteMatch, RouteMode, RouteOptions, RoutePolicy, RouteQuery, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot };
|
|
197
204
|
//# sourceMappingURL=router.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","names":[],"sources":["../../src/common/router.ts"],"mappings":";;AAUA;;;;;AAEA;;;KAFY,cAAA,IAAkB,KAAA,EAAO,MAAA;AAAA,KAEzB,SAAA;AAAA,KACA,aAAA;AAAA,KACA,oBAAA;AAAA,KACA,gBAAA;AAAA,UAEK,mBAAA;EACf,IAAA;AAAA;AAAA,UAGe,sBAAA;EACf,IAAA;EACA,EAAA;EACA,MAAA,GAAS,oBAAA;EACT,OAAA;AAAA;AAAA,UAGe,kBAAA;EACf,IAAA;EACA,MAAA,EAAQ,gBAAA;AAAA;AAAA,KAGE,cAAA,GACR,mBAAA,GACA,sBAAA,GACA,kBAAA;AAAA,UAEa,YAAA;EACf,IAAA,EAAM,SAAA;EACN,MAAA,EAAQ,MAAA;EACR,QAAA;EACA,MAAA;EACA,IAAA;EACA,IAAA;EACA,OAAA,EAAS,OAAA;EACT,IAAA,EAAM,IAAA;EACN,MAAA,EAAQ,WAAA;AAAA;AAAA,KAGE,WAAA,IACV,OAAA,EAAS,YAAA,KACN,cAAA,GAAiB,OAAA,CAAQ,cAAA;AAAA,UAEb,cAAA;EACf,OAAA,EAAS,OAAA;EACT,IAAA,EAAM,IAAA;AAAA;AAAA,KAGI,iBAAA,uCACV,OAAA,EAAS,IAAA,CAAK,YAAA,CAAa,OAAA,EAAS,IAAA,2BACjC,cAAA,CAAe,OAAA,EAAS,IAAA,IAAQ,OAAA,CAAQ,cAAA,CAAe,OAAA,EAAS,IAAA;AAAA,UAEpD,gBAAA;EACf,OAAA,EAAS,iBAAA,CAAkB,OAAA,EAAS,IAAA;EACpC,SAAA,cAEM,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,eAAmB,OAAA;EACxD,eAAA,cAEM,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,eAAmB,OAAA;EACxD,OAAA,IACE,IAAA,EAAM,IAAA,EACN,IAAA,UACA,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,gBAClB,OAAA;EACf,aAAA,IACE,IAAA,EAAM,IAAA,EACN,UAAA,UACA,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,gBAClB,OAAA;AAAA;AAAA,UAGA,mBAAA;EACf,IAAA,GAAO,aAAA;EACP,IAAA;EACA,UAAA;EACA,QAAA,YAAoB,WAAA;AAAA;;;;;;;AAjDtB;;UA4DiB,YAAA,SAAqB,mBAAA;EACpC,MAAA,IAAU,OAAA;IAAW,MAAA,EAAQ,MAAA;EAAA;EAC7B,OAAA,SACI,KAAA,CAAM,MAAA,oBACN,OAAA,CAAQ,KAAA,CAAM,MAAA;EAClB,KAAA;EACA,SAAA;AAAA;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"router.d.ts","names":[],"sources":["../../src/common/router.ts"],"mappings":";;AAUA;;;;;AAEA;;;KAFY,cAAA,IAAkB,KAAA,EAAO,MAAA;AAAA,KAEzB,SAAA;AAAA,KACA,aAAA;AAAA,KACA,oBAAA;AAAA,KACA,gBAAA;AAAA,UAEK,mBAAA;EACf,IAAA;AAAA;AAAA,UAGe,sBAAA;EACf,IAAA;EACA,EAAA;EACA,MAAA,GAAS,oBAAA;EACT,OAAA;AAAA;AAAA,UAGe,kBAAA;EACf,IAAA;EACA,MAAA,EAAQ,gBAAA;AAAA;AAAA,KAGE,cAAA,GACR,mBAAA,GACA,sBAAA,GACA,kBAAA;AAAA,UAEa,YAAA;EACf,IAAA,EAAM,SAAA;EACN,MAAA,EAAQ,MAAA;EACR,QAAA;EACA,MAAA;EACA,IAAA;EACA,IAAA;EACA,OAAA,EAAS,OAAA;EACT,IAAA,EAAM,IAAA;EACN,MAAA,EAAQ,WAAA;AAAA;AAAA,KAGE,WAAA,IACV,OAAA,EAAS,YAAA,KACN,cAAA,GAAiB,OAAA,CAAQ,cAAA;AAAA,UAEb,cAAA;EACf,OAAA,EAAS,OAAA;EACT,IAAA,EAAM,IAAA;AAAA;AAAA,KAGI,iBAAA,uCACV,OAAA,EAAS,IAAA,CAAK,YAAA,CAAa,OAAA,EAAS,IAAA,2BACjC,cAAA,CAAe,OAAA,EAAS,IAAA,IAAQ,OAAA,CAAQ,cAAA,CAAe,OAAA,EAAS,IAAA;AAAA,UAEpD,gBAAA;EACf,OAAA,EAAS,iBAAA,CAAkB,OAAA,EAAS,IAAA;EACpC,SAAA,cAEM,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,eAAmB,OAAA;EACxD,eAAA,cAEM,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,eAAmB,OAAA;EACxD,OAAA,IACE,IAAA,EAAM,IAAA,EACN,IAAA,UACA,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,gBAClB,OAAA;EACf,aAAA,IACE,IAAA,EAAM,IAAA,EACN,UAAA,UACA,OAAA,EAAS,YAAA,CAAa,OAAA,EAAS,IAAA,gBAClB,OAAA;AAAA;AAAA,UAGA,mBAAA;EACf,IAAA,GAAO,aAAA;EACP,IAAA;EACA,UAAA;EACA,QAAA,YAAoB,WAAA;AAAA;;;;;;;AAjDtB;;UA4DiB,YAAA,SAAqB,mBAAA;EACpC,MAAA,IAAU,OAAA;IAAW,MAAA,EAAQ,MAAA;EAAA;EAC7B,OAAA,SACI,KAAA,CAAM,MAAA,oBACN,OAAA,CAAQ,KAAA,CAAM,MAAA;EAClB,KAAA;EACA,SAAA;AAAA;AAAA,UAGe,iBAAA,SAA0B,mBAAA;;;;;;;;;UAU1B,aAAA;EACf,IAAA;EAxEA;EA0EA,KAAA;AAAA;;UAIe,iBAAA;EACf,SAAA,GAAY,KAAA;IAAS,QAAA;EAAA;AAAA;;UAIN,eAAA;EACf,SAAA,EAAW,cAAA;AAAA;AAAA,UAGI,qBAAA;EACf,IAAA,GAAO,gBAAA;AAAA;AAAA,KAGG,eAAA;AAAA,UAEK,mBAAA;EACf,QAAA,GAAW,aAAA;EACX,IAAA,GAAO,SAAA;EACP,IAAA,GAAO,gBAAA;EACP,MAAA,GAAS,WAAA;AAAA;AAAA,UAGM,iBAAA;EACf,IAAA;EACA,OAAA,EAAS,YAAA;EACT,MAAA,EAAQ,MAAA;AAAA;AAAA,KAGE,kBAAA,GACR,iBAAA,GACA,sBAAA,GACA,kBAAA;AAAA,UAGa,kBAAA,SAA2B,mBAAA;EAC1C,MAAA,IAAU,KAAA;IAAS,QAAA;EAAA;AAAA;AApGrB;;;;;;;;AAAA,UA+GiB,WAAA;EA7GZ;EA+GH,IAAA;EA/GmE;EAiHnE,SAAA,EAAW,cAAA;EAjHwB;EAmHnC,QAAA,EAAU,aAAA;EAnHgC;EAqH1C,IAAA;EAvH+C;EAyH/C,WAAA,EAAa,iBAAA;EAxHC;EA0Hd,SAAA,EAAW,eAAA;EA1HyB;EA4HpC,OAAA,EAAS,YAAA;EA3HN;EA6HH,UAAA;EA7H2B;;;;;EAmI3B,OAAA,EAAS,YAAA;AAAA;AAjIX;;;;;;;;;;AAAA,UA8IiB,aAAA;EACf,OAAA,EAAS,WAAA;EACT,IAAA,GAAO,gBAAA;AAAA;AAAA,UAGQ,YAAA;EAAA,CACd,MAAA,EAAQ,MAAA,kBAAwB,OAAA;IAAY,MAAA,EAAQ,WAAA;EAAA;AAAA;AAAA,UAGtC,KAAA;EACf,IAAA;EACA,OAAA,EAAS,YAAA;EACT,SAAA;AAAA;AAAA,UAGe,aAAA;EACf,OAAA,EAAS,YAAA;EACT,MAAA,EAAQ,MAAA;AAAA;AAAA,UAGO,UAAA;EACf,IAAA;EACA,MAAA,EAAQ,QAAA,CAAS,MAAA;EACjB,IAAA;EACA,SAAA;AAAA;AAAA,UAGe,UAAA;EACf,GAAA,CAAI,GAAA;EACJ,MAAA,CAAO,GAAA;EACP,GAAA,CAAI,GAAA;EACJ,MAAA,IAAU,MAAA;AAAA;AAAA,UAGK,aAAA;EACf,IAAA;EACA,MAAA,EAAQ,QAAA,CAAS,MAAA;EACjB,KAAA,EAAO,QAAA,CAAS,UAAA;EAChB,IAAA;EAEA,IAAA;EACA,SAAA;EACA,OAAA,WAAkB,UAAA;AAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { State, state } from "./runtime/state.js";
|
|
|
4
4
|
import { Context, defineContext, readContext } from "./runtime/context.js";
|
|
5
5
|
import { getSignal } from "./runtime/component.js";
|
|
6
6
|
import { For, ForProps } from "./control/for.js";
|
|
7
|
-
import { AccessDecision, AccessDenyDecision, AccessRedirectDecision, GroupHelperOptions, RegisterRoutesOptions, RouteAuthMode, RouteAuthOptions, RouteAuthResolver, RouteAuthState, RouteComponent, RouteContext, RouteDefinition, RouteManifest, RouteMatch, RouteMode, RouteOptions, RoutePolicy, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot } from "./common/router.js";
|
|
7
|
+
import { AccessDecision, AccessDenyDecision, AccessRedirectDecision, GroupHelperOptions, PageHelperOptions, PageScopeRecord, RegisterRoutesOptions, RouteAuthMode, RouteAuthOptions, RouteAuthResolver, RouteAuthState, RouteComponent, RouteContext, RouteDefinition, RouteManifest, RouteMatch, RouteMode, RouteOptions, RoutePolicy, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot } from "./common/router.js";
|
|
8
8
|
import { HistoryScrollBehavior, NavigateOptions, NavigationScrollBehavior, ScrollRestorationOptions, navigate } from "./router/navigate.js";
|
|
9
9
|
import { HydrateSPAConfig, IslandConfig, IslandsConfig, SPAConfig, cleanupApp, createIsland, createIslands, createSPA, hasApp, hydrateSPA } from "./boot/index.js";
|
|
10
10
|
import { Show, ShowProps } from "./control/show.js";
|
|
@@ -16,8 +16,8 @@ import { Derived, derive } from "./runtime/derive.js";
|
|
|
16
16
|
import { Selector, selector } from "./runtime/selector.js";
|
|
17
17
|
import { ResourceResult, resource } from "./runtime/operations.js";
|
|
18
18
|
import { Mutation, Query, QueryConsistency, createMutation, createQuery, invalidate } from "./data/index.js";
|
|
19
|
-
import { currentRoute, fallback, group, lazy, registerRoutes, resolveRouteRequest, route } from "./router/route.js";
|
|
19
|
+
import { Outlet, currentRoute, fallback, group, index, lazy, page, registerRoutes, resolveRouteRequest, route } from "./router/route.js";
|
|
20
20
|
import { allow, deny, forbidden, notFound, redirect, requireAuth, requirePermission, requireRole, unauthorized } from "./router/policy.js";
|
|
21
21
|
import { Link, LinkProps } from "./components/link.js";
|
|
22
22
|
import { ErrorBoundary, ErrorBoundaryFallbackRender, ErrorBoundaryProps } from "./components/error-boundary.js";
|
|
23
|
-
export { type AccessDecision, type AccessDenyDecision, type AccessRedirectDecision, Case, type CaseProps, type Context, DefaultPortal, type Derived, ErrorBoundary, type ErrorBoundaryFallbackRender, type ErrorBoundaryProps, For, type ForProps, Fragment, type GroupHelperOptions, type HistoryScrollBehavior, type HydrateSPAConfig, type IslandConfig, type IslandsConfig, Link, type LinkProps, Match, type MatchProps, type Mutation, type NavigateOptions, type NavigationScrollBehavior, Portal, type PortalProps, type Props, type Query, type QueryConsistency, type RegisterRoutesOptions, type ResourceResult, type RouteAuthMode, type RouteAuthOptions, type RouteAuthResolver, type RouteAuthState, type RouteComponent, type RouteContext, type RouteDefinition, type RouteManifest, type RouteMatch, type RouteMode, type RouteOptions, type RoutePolicy, type RouteRecord, type RouteRenderResult, type RouteRequestOptions, type RouteRequestResult, type RouteSnapshot, type SPAConfig, type ScrollRestorationOptions, type Selector, Show, type ShowProps, Slot, type SlotProps, type State, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, invalidate, jsx, jsxs, lazy, navigate, notFound, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, resource, route, selector, state, unauthorized };
|
|
23
|
+
export { type AccessDecision, type AccessDenyDecision, type AccessRedirectDecision, Case, type CaseProps, type Context, DefaultPortal, type Derived, ErrorBoundary, type ErrorBoundaryFallbackRender, type ErrorBoundaryProps, For, type ForProps, Fragment, type GroupHelperOptions, type HistoryScrollBehavior, type HydrateSPAConfig, type IslandConfig, type IslandsConfig, Link, type LinkProps, Match, type MatchProps, type Mutation, type NavigateOptions, type NavigationScrollBehavior, Outlet, type PageHelperOptions, type PageScopeRecord, Portal, type PortalProps, type Props, type Query, type QueryConsistency, type RegisterRoutesOptions, type ResourceResult, type RouteAuthMode, type RouteAuthOptions, type RouteAuthResolver, type RouteAuthState, type RouteComponent, type RouteContext, type RouteDefinition, type RouteManifest, type RouteMatch, type RouteMode, type RouteOptions, type RoutePolicy, type RouteRecord, type RouteRenderResult, type RouteRequestOptions, type RouteRequestResult, type RouteSnapshot, type SPAConfig, type ScrollRestorationOptions, type Selector, Show, type ShowProps, Slot, type SlotProps, type State, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, index, invalidate, jsx, jsxs, lazy, navigate, notFound, page, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, resource, route, selector, state, unauthorized };
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { selector } from "./runtime/selector.js";
|
|
|
10
10
|
import { resource } from "./runtime/operations.js";
|
|
11
11
|
import { createMutation, createQuery, invalidate } from "./data/index.js";
|
|
12
12
|
import { allow, deny, forbidden, notFound, redirect, requireAuth, requirePermission, requireRole, unauthorized } from "./router/policy.js";
|
|
13
|
-
import { currentRoute, fallback, group, lazy, registerRoutes, resolveRouteRequest, route } from "./router/route.js";
|
|
13
|
+
import { Outlet, currentRoute, fallback, group, index, lazy, page, registerRoutes, resolveRouteRequest, route } from "./router/route.js";
|
|
14
14
|
import { DefaultPortal, Portal, definePortal } from "./foundations/structures/portal.js";
|
|
15
15
|
import { navigate } from "./router/navigate.js";
|
|
16
16
|
import { cleanupApp, createIsland, createIslands, createSPA, hasApp, hydrateSPA } from "./boot/index.js";
|
|
@@ -31,6 +31,6 @@ import "./foundations/structures.js";
|
|
|
31
31
|
*/
|
|
32
32
|
installRendererBridge();
|
|
33
33
|
//#endregion
|
|
34
|
-
export { Case, DefaultPortal, ErrorBoundary, For, Fragment, Link, Match, Portal, Show, Slot, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, invalidate, jsx, jsxs, lazy, navigate, notFound, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, resource, route, selector, state, unauthorized };
|
|
34
|
+
export { Case, DefaultPortal, ErrorBoundary, For, Fragment, Link, Match, Outlet, Portal, Show, Slot, allow, cleanupApp, createIsland, createIslands, createMutation, createQuery, createSPA, currentRoute, defineContext, definePortal, deny, derive, fallback, forbidden, getSignal, group, hasApp, hydrateSPA, index, invalidate, jsx, jsxs, lazy, navigate, notFound, page, readContext, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, resource, route, selector, state, unauthorized };
|
|
35
35
|
|
|
36
36
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Askr: Actor-backed deterministic UI framework\n *\n * Public API surface — only users should import from here\n */\n\nimport { installRendererBridge } from './renderer';\n\ninstallRendererBridge();\n\n// Runtime primitives\nexport { state } from './runtime/state';\nexport type { State } from './runtime/state';\nexport { derive } from './runtime/derive';\nexport type { Derived } from './runtime/derive';\nexport { getSignal } from './runtime/component';\nexport { selector } from './runtime/selector';\nexport type { Selector } from './runtime/selector';\n\n// Context\nexport { defineContext, readContext } from './runtime/context';\nexport type { Context } from './runtime/context';\n\n// Resources\nexport { resource } from './runtime/operations';\nexport type { ResourceResult } from './runtime/operations';\n\n// Data\nexport { createQuery, createMutation, invalidate } from './data';\nexport type { Query, Mutation, QueryConsistency } from './data';\n\n// App bootstrap\nexport {\n createIsland,\n createIslands,\n createSPA,\n hydrateSPA,\n cleanupApp,\n hasApp,\n} from './boot';\nexport type {\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n HydrateSPAConfig,\n} from './boot';\n\n// Routing\nexport {\n registerRoutes,\n route,\n currentRoute,\n group,\n fallback,\n lazy,\n allow,\n redirect,\n deny,\n unauthorized,\n forbidden,\n notFound,\n requireAuth,\n requireRole,\n requirePermission,\n resolveRouteRequest,\n type RouteSnapshot,\n type RouteMatch,\n type RouteComponent,\n type RouteMode,\n type RouteAuthMode,\n type RouteContext,\n type RoutePolicy,\n type RouteOptions,\n type RouteRecord,\n type RouteManifest,\n type AccessDecision,\n type AccessDenyDecision,\n type AccessRedirectDecision,\n type GroupHelperOptions,\n type RegisterRoutesOptions,\n type RouteDefinition,\n type RouteAuthOptions,\n type RouteAuthResolver,\n type RouteAuthState,\n type RouteRenderResult,\n type RouteRequestOptions,\n type RouteRequestResult,\n} from './router';\nexport { navigate } from './router/navigate';\nexport type {\n NavigateOptions,\n NavigationScrollBehavior,\n HistoryScrollBehavior,\n ScrollRestorationOptions,\n} from './router/navigate';\n\n// Components\nexport { Link } from './components/link';\nexport type { LinkProps } from './components/link';\nexport { ErrorBoundary } from './components/error-boundary';\nexport type {\n ErrorBoundaryProps,\n ErrorBoundaryFallbackRender,\n} from './components/error-boundary';\nexport { Case, For, Match, Show } from './control';\nexport type { CaseProps, ForProps, MatchProps, ShowProps } from './control';\nexport {\n Slot,\n definePortal,\n DefaultPortal,\n Portal,\n} from './foundations/structures';\nexport type { SlotProps, PortalProps } from './foundations/structures';\n\n// Re-export JSX runtime for tsconfig jsxImportSource\nexport { jsx, jsxs, Fragment } from './jsx-runtime';\n\n// Public types\nexport type { Props } from './common/props';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,uBAAuB"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Askr: Actor-backed deterministic UI framework\n *\n * Public API surface — only users should import from here\n */\n\nimport { installRendererBridge } from './renderer';\n\ninstallRendererBridge();\n\n// Runtime primitives\nexport { state } from './runtime/state';\nexport type { State } from './runtime/state';\nexport { derive } from './runtime/derive';\nexport type { Derived } from './runtime/derive';\nexport { getSignal } from './runtime/component';\nexport { selector } from './runtime/selector';\nexport type { Selector } from './runtime/selector';\n\n// Context\nexport { defineContext, readContext } from './runtime/context';\nexport type { Context } from './runtime/context';\n\n// Resources\nexport { resource } from './runtime/operations';\nexport type { ResourceResult } from './runtime/operations';\n\n// Data\nexport { createQuery, createMutation, invalidate } from './data';\nexport type { Query, Mutation, QueryConsistency } from './data';\n\n// App bootstrap\nexport {\n createIsland,\n createIslands,\n createSPA,\n hydrateSPA,\n cleanupApp,\n hasApp,\n} from './boot';\nexport type {\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n HydrateSPAConfig,\n} from './boot';\n\n// Routing\nexport {\n registerRoutes,\n route,\n page,\n index,\n Outlet,\n currentRoute,\n group,\n fallback,\n lazy,\n allow,\n redirect,\n deny,\n unauthorized,\n forbidden,\n notFound,\n requireAuth,\n requireRole,\n requirePermission,\n resolveRouteRequest,\n type RouteSnapshot,\n type RouteMatch,\n type RouteComponent,\n type RouteMode,\n type RouteAuthMode,\n type RouteContext,\n type RoutePolicy,\n type RouteOptions,\n type RouteRecord,\n type RouteManifest,\n type PageScopeRecord,\n type AccessDecision,\n type AccessDenyDecision,\n type AccessRedirectDecision,\n type GroupHelperOptions,\n type PageHelperOptions,\n type RegisterRoutesOptions,\n type RouteDefinition,\n type RouteAuthOptions,\n type RouteAuthResolver,\n type RouteAuthState,\n type RouteRenderResult,\n type RouteRequestOptions,\n type RouteRequestResult,\n} from './router';\nexport { navigate } from './router/navigate';\nexport type {\n NavigateOptions,\n NavigationScrollBehavior,\n HistoryScrollBehavior,\n ScrollRestorationOptions,\n} from './router/navigate';\n\n// Components\nexport { Link } from './components/link';\nexport type { LinkProps } from './components/link';\nexport { ErrorBoundary } from './components/error-boundary';\nexport type {\n ErrorBoundaryProps,\n ErrorBoundaryFallbackRender,\n} from './components/error-boundary';\nexport { Case, For, Match, Show } from './control';\nexport type { CaseProps, ForProps, MatchProps, ShowProps } from './control';\nexport {\n Slot,\n definePortal,\n DefaultPortal,\n Portal,\n} from './foundations/structures';\nexport type { SlotProps, PortalProps } from './foundations/structures';\n\n// Re-export JSX runtime for tsconfig jsxImportSource\nexport { jsx, jsxs, Fragment } from './jsx-runtime';\n\n// Public types\nexport type { Props } from './common/props';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,uBAAuB"}
|
package/dist/router/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AccessDecision, AccessDenyDecision, AccessRedirectDecision, GroupHelperOptions, LayoutScopeRecord, ParsedSegment, RegisterRoutesOptions, Route, RouteAuthMode, RouteAuthOptions, RouteAuthResolver, RouteAuthState, RouteComponent, RouteContext, RouteDefinition, RouteHandler, RouteManifest, RouteMatch, RouteMode, RouteOptions, RoutePolicy, RouteQuery, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot } from "../common/router.js";
|
|
1
|
+
import { AccessDecision, AccessDenyDecision, AccessRedirectDecision, GroupHelperOptions, LayoutScopeRecord, PageHelperOptions, PageScopeRecord, ParsedSegment, RegisterRoutesOptions, Route, RouteAuthMode, RouteAuthOptions, RouteAuthResolver, RouteAuthState, RouteComponent, RouteContext, RouteDefinition, RouteHandler, RouteManifest, RouteMatch, RouteMode, RouteOptions, RoutePolicy, RouteQuery, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot } from "../common/router.js";
|
|
2
2
|
import { HistoryScrollBehavior, NavigateOptions, NavigationScrollBehavior, ScrollRestorationOptions, navigate } from "./navigate.js";
|
|
3
|
-
import { _applyManifest, _drainLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, lazy, registerRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace } from "./route.js";
|
|
3
|
+
import { Outlet, _applyManifest, _drainLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, index, lazy, page, registerRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace } from "./route.js";
|
|
4
4
|
import { allow, deny, forbidden, notFound, redirect, requireAuth, requirePermission, requireRole, unauthorized } from "./policy.js";
|
|
5
5
|
import { Link, LinkProps } from "../components/link.js";
|
|
6
|
-
export { type AccessDecision, type AccessDenyDecision, type AccessRedirectDecision, type GroupHelperOptions, type HistoryScrollBehavior, type LayoutScopeRecord, Link, type LinkProps, type NavigateOptions, type NavigationScrollBehavior, type ParsedSegment, type RegisterRoutesOptions, type Route, type RouteAuthMode, type RouteAuthOptions, type RouteAuthResolver, type RouteAuthState, type RouteComponent, type RouteContext, type RouteDefinition, type RouteHandler, type RouteManifest, type RouteMatch, type RouteMode, type RouteOptions, type RoutePolicy, type RouteQuery, type RouteRecord, type RouteRenderResult, type RouteRequestOptions, type RouteRequestResult, type RouteSnapshot, type ScrollRestorationOptions, _applyManifest, _drainLazy, allow, clearRoutes, currentRoute, deny, fallback, forbidden, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, lazy, navigate, notFound, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, route, setServerLocation, unauthorized, unloadNamespace };
|
|
6
|
+
export { type AccessDecision, type AccessDenyDecision, type AccessRedirectDecision, type GroupHelperOptions, type HistoryScrollBehavior, type LayoutScopeRecord, Link, type LinkProps, type NavigateOptions, type NavigationScrollBehavior, Outlet, type PageHelperOptions, type PageScopeRecord, type ParsedSegment, type RegisterRoutesOptions, type Route, type RouteAuthMode, type RouteAuthOptions, type RouteAuthResolver, type RouteAuthState, type RouteComponent, type RouteContext, type RouteDefinition, type RouteHandler, type RouteManifest, type RouteMatch, type RouteMode, type RouteOptions, type RoutePolicy, type RouteQuery, type RouteRecord, type RouteRenderResult, type RouteRequestOptions, type RouteRequestResult, type RouteSnapshot, type ScrollRestorationOptions, _applyManifest, _drainLazy, allow, clearRoutes, currentRoute, deny, fallback, forbidden, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, index, lazy, navigate, notFound, page, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, route, setServerLocation, unauthorized, unloadNamespace };
|
package/dist/router/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { allow, deny, forbidden, notFound, redirect, requireAuth, requirePermission, requireRole, unauthorized } from "./policy.js";
|
|
2
|
-
import { _applyManifest, _drainLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, lazy, registerRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace } from "./route.js";
|
|
2
|
+
import { Outlet, _applyManifest, _drainLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, index, lazy, page, registerRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace } from "./route.js";
|
|
3
3
|
import { navigate } from "./navigate.js";
|
|
4
4
|
import { Link } from "../components/link.js";
|
|
5
|
-
export { Link, _applyManifest, _drainLazy, allow, clearRoutes, currentRoute, deny, fallback, forbidden, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, lazy, navigate, notFound, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, route, setServerLocation, unauthorized, unloadNamespace };
|
|
5
|
+
export { Link, Outlet, _applyManifest, _drainLazy, allow, clearRoutes, currentRoute, deny, fallback, forbidden, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, index, lazy, navigate, notFound, page, redirect, registerRoutes, requireAuth, requirePermission, requireRole, resolveRouteRequest, route, setServerLocation, unauthorized, unloadNamespace };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigate.d.ts","names":[],"sources":["../../src/router/navigate.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"navigate.d.ts","names":[],"sources":["../../src/router/navigate.ts"],"mappings":";;;KA0BY,wBAAA;AAAA,KACA,qBAAA;AAAA,KAEA,wBAAA;EACV,UAAA,GAAa,wBAAA;EACb,OAAA,GAAU,qBAAA;AAAA;AAAA,KAqBA,eAAA;EACV,OAAA;EACA,MAAA,GAAS,wBAAA;AAAA;AAAA,iBAsIK,0BAAA,CACd,OAAA,aAAoB,wBAAA;;iBAkPN,mBAAA,CACd,QAAA,EAAU,iBAAA,EACV,IAAA;;;;;iBAsBc,QAAA,CAAS,IAAA,UAAc,OAAA,GAAS,eAAA;;AAnZhD;;iBAqegB,oBAAA,CAAA;;;;iBASA,iBAAA,CAAA"}
|
package/dist/router/navigate.js
CHANGED
|
@@ -2,7 +2,7 @@ import { isDevelopmentEnvironment, isProductionEnvironment } from "../common/env
|
|
|
2
2
|
import { logger } from "../dev/logger.js";
|
|
3
3
|
import { ELEMENT_TYPE, Fragment } from "../common/jsx.js";
|
|
4
4
|
import { mountComponent } from "../runtime/component.js";
|
|
5
|
-
import { lockRouteRegistration, resolveRoute, resolveRouteRequest } from "./route.js";
|
|
5
|
+
import { lockRouteRegistration, resolveRoute, resolveRouteRequest, syncCurrentRouteSnapshot } from "./route.js";
|
|
6
6
|
import "../jsx/index.js";
|
|
7
7
|
import { DefaultPortal } from "../foundations/structures/portal.js";
|
|
8
8
|
//#region src/router/navigate.ts
|
|
@@ -211,6 +211,7 @@ function applyNavigationTarget(path, options, target) {
|
|
|
211
211
|
};
|
|
212
212
|
const historyMethod = options.history === "replace" ? "replaceState" : "pushState";
|
|
213
213
|
window.history[historyMethod]({ path: href }, "", href);
|
|
214
|
+
syncCurrentRouteSnapshot(window.location.pathname, window.location.search, window.location.hash);
|
|
214
215
|
if (currentInstance) {
|
|
215
216
|
if (pathname === currentPathname && isRenderResult(resolved)) {
|
|
216
217
|
rerenderResolvedRoute(pathname, href);
|
|
@@ -225,6 +226,7 @@ function registerAppInstance(instance, path) {
|
|
|
225
226
|
currentInstance = instance;
|
|
226
227
|
currentPathname = path;
|
|
227
228
|
currentHref = getWindowHref();
|
|
229
|
+
syncCurrentRouteSnapshot(window.location.pathname, window.location.search, window.location.hash);
|
|
228
230
|
saveScrollPosition(currentHref);
|
|
229
231
|
if (isProductionEnvironment()) lockRouteRegistration();
|
|
230
232
|
}
|
|
@@ -260,6 +262,7 @@ function handlePopState(_event) {
|
|
|
260
262
|
navigate(resolved.to, { history: "replace" });
|
|
261
263
|
return;
|
|
262
264
|
}
|
|
265
|
+
syncCurrentRouteSnapshot(window.location.pathname, window.location.search, window.location.hash);
|
|
263
266
|
if (pathname === currentPathname && isRenderResult(resolved)) {
|
|
264
267
|
rerenderResolvedRoute(pathname, href);
|
|
265
268
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigate.js","names":[],"sources":["../../src/router/navigate.ts"],"sourcesContent":["/**\n * Client-side navigation with History API\n */\n\nimport {\n resolveRoute,\n resolveRouteRequest,\n lockRouteRegistration,\n type ResolvedRoute,\n} from './route';\nimport { mountComponent, type ComponentInstance } from '../runtime/component';\nimport {\n isDevelopmentEnvironment,\n isProductionEnvironment,\n} from '../common/env';\nimport { logger } from '../dev/logger';\nimport type { RouteRenderResult, RouteRequestResult } from '../common/router';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport { DefaultPortal } from '../foundations/structures/portal';\n\n// Global app state for navigation\nlet currentInstance: ComponentInstance | null = null;\nlet currentPathname = '/';\nlet currentHref = '/';\n\nexport type NavigationScrollBehavior = 'top' | 'preserve';\nexport type HistoryScrollBehavior = 'restore' | 'top' | 'preserve';\n\nexport type ScrollRestorationOptions = {\n navigation?: NavigationScrollBehavior;\n history?: HistoryScrollBehavior;\n};\n\ntype NormalizedScrollRestorationOptions = {\n enabled: boolean;\n navigation: NavigationScrollBehavior;\n history: HistoryScrollBehavior;\n};\n\nconst DEFAULT_SCROLL_RESTORATION: NormalizedScrollRestorationOptions = {\n enabled: true,\n navigation: 'top',\n history: 'restore',\n};\n\nlet scrollRestorationOptions: NormalizedScrollRestorationOptions = {\n ...DEFAULT_SCROLL_RESTORATION,\n};\n\nconst scrollPositions = new Map<string, { x: number; y: number }>();\n\nexport type NavigateOptions = {\n history?: 'push' | 'replace';\n scroll?: NavigationScrollBehavior;\n};\n\nfunction getWindowHref(): string {\n if (typeof window === 'undefined') {\n return currentHref;\n }\n\n return `${window.location.pathname}${window.location.search}${window.location.hash}`;\n}\n\nfunction normalizeScrollRestorationOptions(\n options?: boolean | ScrollRestorationOptions\n): NormalizedScrollRestorationOptions {\n if (options === false) {\n return {\n enabled: false,\n navigation: DEFAULT_SCROLL_RESTORATION.navigation,\n history: DEFAULT_SCROLL_RESTORATION.history,\n };\n }\n\n if (options === true || options === undefined) {\n return { ...DEFAULT_SCROLL_RESTORATION };\n }\n\n return {\n enabled: true,\n navigation: options.navigation ?? DEFAULT_SCROLL_RESTORATION.navigation,\n history: options.history ?? DEFAULT_SCROLL_RESTORATION.history,\n };\n}\n\nfunction readScrollPosition(): { x: number; y: number } {\n if (typeof window === 'undefined') {\n return { x: 0, y: 0 };\n }\n\n const x =\n typeof window.scrollX === 'number'\n ? window.scrollX\n : typeof window.pageXOffset === 'number'\n ? window.pageXOffset\n : 0;\n const y =\n typeof window.scrollY === 'number'\n ? window.scrollY\n : typeof window.pageYOffset === 'number'\n ? window.pageYOffset\n : 0;\n\n return { x, y };\n}\n\nfunction writeHistoryScrollPosition(\n href: string,\n position: { x: number; y: number }\n): void {\n if (typeof window === 'undefined' || getWindowHref() !== href) {\n return;\n }\n if (typeof window.history?.replaceState !== 'function') {\n return;\n }\n const state =\n window.history.state && typeof window.history.state === 'object'\n ? window.history.state\n : {};\n\n window.history.replaceState(\n {\n ...state,\n path: href,\n scroll: position,\n },\n '',\n href\n );\n}\n\nfunction saveScrollPosition(href: string): void {\n if (!scrollRestorationOptions.enabled || typeof window === 'undefined') {\n return;\n }\n\n const position = readScrollPosition();\n scrollPositions.set(href, position);\n writeHistoryScrollPosition(href, position);\n}\n\nfunction scrollToPosition(position: { x: number; y: number }): void {\n if (typeof window === 'undefined' || typeof window.scrollTo !== 'function') {\n return;\n }\n\n window.scrollTo(position.x, position.y);\n}\n\nfunction applyNavigationScroll(behavior: NavigationScrollBehavior): void {\n if (!scrollRestorationOptions.enabled || behavior === 'preserve') {\n return;\n }\n\n scrollToPosition({ x: 0, y: 0 });\n}\n\nfunction applyHistoryScroll(href: string, state: PopStateEvent['state']): void {\n if (!scrollRestorationOptions.enabled) {\n return;\n }\n\n if (scrollRestorationOptions.history === 'preserve') {\n return;\n }\n\n if (scrollRestorationOptions.history === 'top') {\n scrollToPosition({ x: 0, y: 0 });\n return;\n }\n\n const fromState =\n state && typeof state === 'object' && 'scroll' in state\n ? (state.scroll as { x?: unknown; y?: unknown })\n : undefined;\n const saved =\n fromState &&\n typeof fromState.x === 'number' &&\n typeof fromState.y === 'number'\n ? { x: fromState.x, y: fromState.y }\n : scrollPositions.get(href);\n\n scrollToPosition(saved ?? { x: 0, y: 0 });\n}\n\nexport function configureScrollRestoration(\n options?: boolean | ScrollRestorationOptions\n): void {\n scrollRestorationOptions = normalizeScrollRestorationOptions(options);\n\n if (typeof window === 'undefined') {\n return;\n }\n\n if ('scrollRestoration' in window.history) {\n try {\n window.history.scrollRestoration = scrollRestorationOptions.enabled\n ? 'manual'\n : 'auto';\n } catch {\n // Ignore environments that expose but do not allow setting scrollRestoration.\n }\n }\n}\n\nfunction parseTargetUrl(path: string): URL {\n const pathname = window.location.pathname || '/';\n const search = window.location.search || '';\n const hash = window.location.hash || '';\n const href =\n typeof window.location.href === 'string' ? window.location.href : '';\n const base =\n href &&\n href !== 'about:blank' &&\n !href.startsWith('about:') &&\n !href.startsWith('data:')\n ? href\n : `http://localhost${pathname}${search}${hash}`;\n\n return new URL(path, base);\n}\n\nfunction isRenderResult(\n result: RouteRequestResult\n): result is RouteRenderResult {\n return result !== null && result.kind === 'render';\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return value instanceof Promise;\n}\n\nfunction createDeniedResolvedRoute(status: number): ResolvedRoute {\n return {\n handler: () => ({\n type: 'div',\n props: {\n 'data-route-denied': String(status),\n },\n children: [String(status)],\n }),\n params: {},\n };\n}\n\nfunction bindResolvedRouteHandler(\n resolved: ResolvedRoute\n): ComponentInstance['fn'] {\n return () =>\n resolved.handler(resolved.params) as ReturnType<ComponentInstance['fn']>;\n}\n\nfunction wrapRootRouteHandler(\n componentFn: ComponentInstance['fn']\n): ComponentInstance['fn'] {\n const wrappedFn: ComponentInstance['fn'] = (props, ctx) => {\n const out = componentFn(props, ctx);\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: {},\n key: '__default_portal',\n } as unknown;\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: {\n children:\n out === undefined || out === null\n ? [portalVNode]\n : [out, portalVNode],\n },\n } as ReturnType<ComponentInstance['fn']>;\n };\n\n Object.defineProperty(wrappedFn, 'name', {\n value: componentFn.name || 'Component',\n });\n\n return wrappedFn;\n}\n\nfunction remountResolvedRoute(\n resolved: ResolvedRoute,\n pathname: string,\n href: string\n): boolean {\n if (!currentInstance) {\n return false;\n }\n\n // The route handler IS the component function\n // It takes params as props and renders the route\n currentInstance.fn = wrapRootRouteHandler(bindResolvedRouteHandler(resolved));\n currentInstance.props = {};\n\n // Reset state to prevent leakage from previous route\n // Each route navigation starts completely fresh\n currentInstance.stateValues = [];\n currentInstance.expectedStateIndices = [];\n currentInstance.firstRenderComplete = false;\n currentInstance.stateIndexCheck = -1;\n // Increment generation to invalidate pending async evaluations from previous route\n currentInstance.evaluationGeneration++;\n currentInstance.notifyUpdate = null;\n currentInstance.mountOperations = [];\n currentInstance._placeholder = undefined;\n currentInstance.hasPendingUpdate = false;\n\n // Route-local async work should create a fresh abort controller lazily.\n currentInstance.abortController = null;\n\n // Re-execute component against the existing host so reconciliation can\n // preserve any shared layout DOM between sibling routes.\n mountComponent(currentInstance);\n currentPathname = pathname;\n currentHref = href;\n return true;\n}\n\nfunction rerenderResolvedRoute(pathname: string, href: string): boolean {\n if (!currentInstance) {\n return false;\n }\n\n const resolved = resolveRoute(pathname);\n if (!resolved) {\n return false;\n }\n\n currentPathname = pathname;\n currentHref = href;\n currentInstance._enqueueRun?.();\n return true;\n}\n\nfunction resolveNavigationTarget(path: string) {\n const target = parseTargetUrl(path);\n const pathname = target.pathname;\n const href = `${target.pathname}${target.search}${target.hash}`;\n const resolved = resolveRouteRequest(href);\n\n if (isPromise(resolved)) {\n return resolved.then((next) => ({\n href,\n pathname,\n resolved: next,\n }));\n }\n\n return {\n href,\n pathname,\n resolved,\n };\n}\n\nfunction applyNavigationTarget(\n path: string,\n options: NavigateOptions,\n target: {\n href: string;\n pathname: string;\n resolved: RouteRequestResult;\n }\n): void {\n const { href, pathname, resolved } = target;\n const previousPathname = currentPathname;\n\n saveScrollPosition(currentHref);\n\n if (!resolved) {\n if (isDevelopmentEnvironment()) {\n logger.warn(`No route found for path: ${path}`);\n }\n return;\n }\n\n if (resolved.kind === 'redirect') {\n const redirectTarget = parseTargetUrl(resolved.to);\n const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;\n if (redirectHref === href) {\n if (isDevelopmentEnvironment()) {\n logger.warn(\n `Navigation guard redirected to the same path: ${redirectHref}`\n );\n }\n return;\n }\n\n navigate(redirectHref, { history: 'replace' });\n return;\n }\n\n const nextResolved =\n resolved.kind === 'deny'\n ? createDeniedResolvedRoute(resolved.status)\n : {\n handler: resolved.handler,\n params: resolved.params,\n };\n\n const historyMethod =\n options.history === 'replace' ? 'replaceState' : 'pushState';\n window.history[historyMethod]({ path: href }, '', href);\n\n if (currentInstance) {\n if (pathname === currentPathname && isRenderResult(resolved)) {\n rerenderResolvedRoute(pathname, href);\n return;\n }\n\n remountResolvedRoute(nextResolved, pathname, href);\n if (pathname !== previousPathname) {\n applyNavigationScroll(\n options.scroll ?? scrollRestorationOptions.navigation\n );\n }\n }\n}\n\n/** Register the current app instance (called by createSPA/hydrateSPA). */\nexport function registerAppInstance(\n instance: ComponentInstance,\n path: string\n): void {\n currentInstance = instance;\n currentPathname = path;\n currentHref = getWindowHref();\n saveScrollPosition(currentHref);\n // Lock further route registrations after the app has started — but allow tests to register routes.\n // Enforce only in production to avoid breaking test infra which registers routes dynamically.\n if (isProductionEnvironment()) {\n lockRouteRegistration();\n }\n}\n\n/**\n * Navigate to a new path\n * Updates URL, resolves route, and re-mounts app with new handler\n */\nexport function navigate(path: string, options: NavigateOptions = {}): void {\n if (typeof window === 'undefined') {\n // SSR context\n return;\n }\n\n const target = resolveNavigationTarget(path);\n if (isPromise(target)) {\n void target.then((resolvedTarget) =>\n applyNavigationTarget(path, options, resolvedTarget)\n );\n return;\n }\n\n applyNavigationTarget(path, options, target);\n}\n\n/**\n * Handle browser back/forward buttons\n */\nfunction handlePopState(_event: PopStateEvent): void {\n const previousHref = currentHref;\n const pathname = window.location.pathname;\n const href = `${window.location.pathname}${window.location.search}${window.location.hash}`;\n\n saveScrollPosition(previousHref);\n\n if (!currentInstance) {\n return;\n }\n\n const resolved = resolveRouteRequest(href);\n\n const applyResolved = (resolved: RouteRequestResult) => {\n if (!resolved) {\n if (isDevelopmentEnvironment()) {\n logger.warn(`No route found for path: ${pathname}`);\n }\n return;\n }\n\n if (resolved.kind === 'redirect') {\n navigate(resolved.to, { history: 'replace' });\n return;\n }\n\n if (pathname === currentPathname && isRenderResult(resolved)) {\n rerenderResolvedRoute(pathname, href);\n return;\n }\n\n remountResolvedRoute(\n resolved.kind === 'deny'\n ? createDeniedResolvedRoute(resolved.status)\n : {\n handler: resolved.handler,\n params: resolved.params,\n },\n pathname,\n href\n );\n\n applyHistoryScroll(href, _event.state);\n };\n\n if (isPromise(resolved)) {\n void resolved.then((next) => applyResolved(next));\n return;\n }\n\n applyResolved(resolved);\n}\n\n/**\n * Setup popstate listener for browser navigation\n */\nexport function initializeNavigation(): void {\n if (typeof window !== 'undefined') {\n window.addEventListener('popstate', handlePopState);\n }\n}\n\n/**\n * Cleanup navigation listeners\n */\nexport function cleanupNavigation(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('popstate', handlePopState);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"navigate.js","names":[],"sources":["../../src/router/navigate.ts"],"sourcesContent":["/**\n * Client-side navigation with History API\n */\n\nimport {\n resolveRoute,\n resolveRouteRequest,\n lockRouteRegistration,\n syncCurrentRouteSnapshot,\n type ResolvedRoute,\n} from './route';\nimport { mountComponent, type ComponentInstance } from '../runtime/component';\nimport {\n isDevelopmentEnvironment,\n isProductionEnvironment,\n} from '../common/env';\nimport { logger } from '../dev/logger';\nimport type { RouteRenderResult, RouteRequestResult } from '../common/router';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport { DefaultPortal } from '../foundations/structures/portal';\n\n// Global app state for navigation\nlet currentInstance: ComponentInstance | null = null;\nlet currentPathname = '/';\nlet currentHref = '/';\n\nexport type NavigationScrollBehavior = 'top' | 'preserve';\nexport type HistoryScrollBehavior = 'restore' | 'top' | 'preserve';\n\nexport type ScrollRestorationOptions = {\n navigation?: NavigationScrollBehavior;\n history?: HistoryScrollBehavior;\n};\n\ntype NormalizedScrollRestorationOptions = {\n enabled: boolean;\n navigation: NavigationScrollBehavior;\n history: HistoryScrollBehavior;\n};\n\nconst DEFAULT_SCROLL_RESTORATION: NormalizedScrollRestorationOptions = {\n enabled: true,\n navigation: 'top',\n history: 'restore',\n};\n\nlet scrollRestorationOptions: NormalizedScrollRestorationOptions = {\n ...DEFAULT_SCROLL_RESTORATION,\n};\n\nconst scrollPositions = new Map<string, { x: number; y: number }>();\n\nexport type NavigateOptions = {\n history?: 'push' | 'replace';\n scroll?: NavigationScrollBehavior;\n};\n\nfunction getWindowHref(): string {\n if (typeof window === 'undefined') {\n return currentHref;\n }\n\n return `${window.location.pathname}${window.location.search}${window.location.hash}`;\n}\n\nfunction normalizeScrollRestorationOptions(\n options?: boolean | ScrollRestorationOptions\n): NormalizedScrollRestorationOptions {\n if (options === false) {\n return {\n enabled: false,\n navigation: DEFAULT_SCROLL_RESTORATION.navigation,\n history: DEFAULT_SCROLL_RESTORATION.history,\n };\n }\n\n if (options === true || options === undefined) {\n return { ...DEFAULT_SCROLL_RESTORATION };\n }\n\n return {\n enabled: true,\n navigation: options.navigation ?? DEFAULT_SCROLL_RESTORATION.navigation,\n history: options.history ?? DEFAULT_SCROLL_RESTORATION.history,\n };\n}\n\nfunction readScrollPosition(): { x: number; y: number } {\n if (typeof window === 'undefined') {\n return { x: 0, y: 0 };\n }\n\n const x =\n typeof window.scrollX === 'number'\n ? window.scrollX\n : typeof window.pageXOffset === 'number'\n ? window.pageXOffset\n : 0;\n const y =\n typeof window.scrollY === 'number'\n ? window.scrollY\n : typeof window.pageYOffset === 'number'\n ? window.pageYOffset\n : 0;\n\n return { x, y };\n}\n\nfunction writeHistoryScrollPosition(\n href: string,\n position: { x: number; y: number }\n): void {\n if (typeof window === 'undefined' || getWindowHref() !== href) {\n return;\n }\n if (typeof window.history?.replaceState !== 'function') {\n return;\n }\n const state =\n window.history.state && typeof window.history.state === 'object'\n ? window.history.state\n : {};\n\n window.history.replaceState(\n {\n ...state,\n path: href,\n scroll: position,\n },\n '',\n href\n );\n}\n\nfunction saveScrollPosition(href: string): void {\n if (!scrollRestorationOptions.enabled || typeof window === 'undefined') {\n return;\n }\n\n const position = readScrollPosition();\n scrollPositions.set(href, position);\n writeHistoryScrollPosition(href, position);\n}\n\nfunction scrollToPosition(position: { x: number; y: number }): void {\n if (typeof window === 'undefined' || typeof window.scrollTo !== 'function') {\n return;\n }\n\n window.scrollTo(position.x, position.y);\n}\n\nfunction applyNavigationScroll(behavior: NavigationScrollBehavior): void {\n if (!scrollRestorationOptions.enabled || behavior === 'preserve') {\n return;\n }\n\n scrollToPosition({ x: 0, y: 0 });\n}\n\nfunction applyHistoryScroll(href: string, state: PopStateEvent['state']): void {\n if (!scrollRestorationOptions.enabled) {\n return;\n }\n\n if (scrollRestorationOptions.history === 'preserve') {\n return;\n }\n\n if (scrollRestorationOptions.history === 'top') {\n scrollToPosition({ x: 0, y: 0 });\n return;\n }\n\n const fromState =\n state && typeof state === 'object' && 'scroll' in state\n ? (state.scroll as { x?: unknown; y?: unknown })\n : undefined;\n const saved =\n fromState &&\n typeof fromState.x === 'number' &&\n typeof fromState.y === 'number'\n ? { x: fromState.x, y: fromState.y }\n : scrollPositions.get(href);\n\n scrollToPosition(saved ?? { x: 0, y: 0 });\n}\n\nexport function configureScrollRestoration(\n options?: boolean | ScrollRestorationOptions\n): void {\n scrollRestorationOptions = normalizeScrollRestorationOptions(options);\n\n if (typeof window === 'undefined') {\n return;\n }\n\n if ('scrollRestoration' in window.history) {\n try {\n window.history.scrollRestoration = scrollRestorationOptions.enabled\n ? 'manual'\n : 'auto';\n } catch {\n // Ignore environments that expose but do not allow setting scrollRestoration.\n }\n }\n}\n\nfunction parseTargetUrl(path: string): URL {\n const pathname = window.location.pathname || '/';\n const search = window.location.search || '';\n const hash = window.location.hash || '';\n const href =\n typeof window.location.href === 'string' ? window.location.href : '';\n const base =\n href &&\n href !== 'about:blank' &&\n !href.startsWith('about:') &&\n !href.startsWith('data:')\n ? href\n : `http://localhost${pathname}${search}${hash}`;\n\n return new URL(path, base);\n}\n\nfunction isRenderResult(\n result: RouteRequestResult\n): result is RouteRenderResult {\n return result !== null && result.kind === 'render';\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return value instanceof Promise;\n}\n\nfunction createDeniedResolvedRoute(status: number): ResolvedRoute {\n return {\n handler: () => ({\n type: 'div',\n props: {\n 'data-route-denied': String(status),\n },\n children: [String(status)],\n }),\n params: {},\n };\n}\n\nfunction bindResolvedRouteHandler(\n resolved: ResolvedRoute\n): ComponentInstance['fn'] {\n return () =>\n resolved.handler(resolved.params) as ReturnType<ComponentInstance['fn']>;\n}\n\nfunction wrapRootRouteHandler(\n componentFn: ComponentInstance['fn']\n): ComponentInstance['fn'] {\n const wrappedFn: ComponentInstance['fn'] = (props, ctx) => {\n const out = componentFn(props, ctx);\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: {},\n key: '__default_portal',\n } as unknown;\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: {\n children:\n out === undefined || out === null\n ? [portalVNode]\n : [out, portalVNode],\n },\n } as ReturnType<ComponentInstance['fn']>;\n };\n\n Object.defineProperty(wrappedFn, 'name', {\n value: componentFn.name || 'Component',\n });\n\n return wrappedFn;\n}\n\nfunction remountResolvedRoute(\n resolved: ResolvedRoute,\n pathname: string,\n href: string\n): boolean {\n if (!currentInstance) {\n return false;\n }\n\n // The route handler IS the component function\n // It takes params as props and renders the route\n currentInstance.fn = wrapRootRouteHandler(bindResolvedRouteHandler(resolved));\n currentInstance.props = {};\n\n // Reset state to prevent leakage from previous route\n // Each route navigation starts completely fresh\n currentInstance.stateValues = [];\n currentInstance.expectedStateIndices = [];\n currentInstance.firstRenderComplete = false;\n currentInstance.stateIndexCheck = -1;\n // Increment generation to invalidate pending async evaluations from previous route\n currentInstance.evaluationGeneration++;\n currentInstance.notifyUpdate = null;\n currentInstance.mountOperations = [];\n currentInstance._placeholder = undefined;\n currentInstance.hasPendingUpdate = false;\n\n // Route-local async work should create a fresh abort controller lazily.\n currentInstance.abortController = null;\n\n // Re-execute component against the existing host so reconciliation can\n // preserve any shared layout DOM between sibling routes.\n mountComponent(currentInstance);\n currentPathname = pathname;\n currentHref = href;\n return true;\n}\n\nfunction rerenderResolvedRoute(pathname: string, href: string): boolean {\n if (!currentInstance) {\n return false;\n }\n\n const resolved = resolveRoute(pathname);\n if (!resolved) {\n return false;\n }\n\n currentPathname = pathname;\n currentHref = href;\n currentInstance._enqueueRun?.();\n return true;\n}\n\nfunction resolveNavigationTarget(path: string) {\n const target = parseTargetUrl(path);\n const pathname = target.pathname;\n const href = `${target.pathname}${target.search}${target.hash}`;\n const resolved = resolveRouteRequest(href);\n\n if (isPromise(resolved)) {\n return resolved.then((next) => ({\n href,\n pathname,\n resolved: next,\n }));\n }\n\n return {\n href,\n pathname,\n resolved,\n };\n}\n\nfunction applyNavigationTarget(\n path: string,\n options: NavigateOptions,\n target: {\n href: string;\n pathname: string;\n resolved: RouteRequestResult;\n }\n): void {\n const { href, pathname, resolved } = target;\n const previousPathname = currentPathname;\n\n saveScrollPosition(currentHref);\n\n if (!resolved) {\n if (isDevelopmentEnvironment()) {\n logger.warn(`No route found for path: ${path}`);\n }\n return;\n }\n\n if (resolved.kind === 'redirect') {\n const redirectTarget = parseTargetUrl(resolved.to);\n const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;\n if (redirectHref === href) {\n if (isDevelopmentEnvironment()) {\n logger.warn(\n `Navigation guard redirected to the same path: ${redirectHref}`\n );\n }\n return;\n }\n\n navigate(redirectHref, { history: 'replace' });\n return;\n }\n\n const nextResolved =\n resolved.kind === 'deny'\n ? createDeniedResolvedRoute(resolved.status)\n : {\n handler: resolved.handler,\n params: resolved.params,\n };\n\n const historyMethod =\n options.history === 'replace' ? 'replaceState' : 'pushState';\n window.history[historyMethod]({ path: href }, '', href);\n syncCurrentRouteSnapshot(\n window.location.pathname,\n window.location.search,\n window.location.hash\n );\n\n if (currentInstance) {\n if (pathname === currentPathname && isRenderResult(resolved)) {\n rerenderResolvedRoute(pathname, href);\n return;\n }\n\n remountResolvedRoute(nextResolved, pathname, href);\n if (pathname !== previousPathname) {\n applyNavigationScroll(\n options.scroll ?? scrollRestorationOptions.navigation\n );\n }\n }\n}\n\n/** Register the current app instance (called by createSPA/hydrateSPA). */\nexport function registerAppInstance(\n instance: ComponentInstance,\n path: string\n): void {\n currentInstance = instance;\n currentPathname = path;\n currentHref = getWindowHref();\n syncCurrentRouteSnapshot(\n window.location.pathname,\n window.location.search,\n window.location.hash\n );\n saveScrollPosition(currentHref);\n // Lock further route registrations after the app has started — but allow tests to register routes.\n // Enforce only in production to avoid breaking test infra which registers routes dynamically.\n if (isProductionEnvironment()) {\n lockRouteRegistration();\n }\n}\n\n/**\n * Navigate to a new path\n * Updates URL, resolves route, and re-mounts app with new handler\n */\nexport function navigate(path: string, options: NavigateOptions = {}): void {\n if (typeof window === 'undefined') {\n // SSR context\n return;\n }\n\n const target = resolveNavigationTarget(path);\n if (isPromise(target)) {\n void target.then((resolvedTarget) =>\n applyNavigationTarget(path, options, resolvedTarget)\n );\n return;\n }\n\n applyNavigationTarget(path, options, target);\n}\n\n/**\n * Handle browser back/forward buttons\n */\nfunction handlePopState(_event: PopStateEvent): void {\n const previousHref = currentHref;\n const pathname = window.location.pathname;\n const href = `${window.location.pathname}${window.location.search}${window.location.hash}`;\n\n saveScrollPosition(previousHref);\n\n if (!currentInstance) {\n return;\n }\n\n const resolved = resolveRouteRequest(href);\n\n const applyResolved = (resolved: RouteRequestResult) => {\n if (!resolved) {\n if (isDevelopmentEnvironment()) {\n logger.warn(`No route found for path: ${pathname}`);\n }\n return;\n }\n\n if (resolved.kind === 'redirect') {\n navigate(resolved.to, { history: 'replace' });\n return;\n }\n\n syncCurrentRouteSnapshot(\n window.location.pathname,\n window.location.search,\n window.location.hash\n );\n\n if (pathname === currentPathname && isRenderResult(resolved)) {\n rerenderResolvedRoute(pathname, href);\n return;\n }\n\n remountResolvedRoute(\n resolved.kind === 'deny'\n ? createDeniedResolvedRoute(resolved.status)\n : {\n handler: resolved.handler,\n params: resolved.params,\n },\n pathname,\n href\n );\n\n applyHistoryScroll(href, _event.state);\n };\n\n if (isPromise(resolved)) {\n void resolved.then((next) => applyResolved(next));\n return;\n }\n\n applyResolved(resolved);\n}\n\n/**\n * Setup popstate listener for browser navigation\n */\nexport function initializeNavigation(): void {\n if (typeof window !== 'undefined') {\n window.addEventListener('popstate', handlePopState);\n }\n}\n\n/**\n * Cleanup navigation listeners\n */\nexport function cleanupNavigation(): void {\n if (typeof window !== 'undefined') {\n window.removeEventListener('popstate', handlePopState);\n }\n}\n"],"mappings":"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"}
|
package/dist/router/route.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import { AccessDecision, AccessDenyDecision, AccessRedirectDecision, GroupHelperOptions, LayoutScopeRecord, ParsedSegment, RegisterRoutesOptions, ResolvedRoute, Route, RouteAuthOptions, RouteComponent, RouteContext, RouteDefinition, RouteHandler, RouteManifest, RouteMatch, RouteOptions, RoutePolicy, RouteQuery, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot } from "../common/router.js";
|
|
1
|
+
import { AccessDecision, AccessDenyDecision, AccessRedirectDecision, GroupHelperOptions, LayoutScopeRecord, PageHelperOptions, PageScopeRecord, ParsedSegment, RegisterRoutesOptions, ResolvedRoute, Route, RouteAuthOptions, RouteComponent, RouteContext, RouteDefinition, RouteHandler, RouteManifest, RouteMatch, RouteOptions, RoutePolicy, RouteQuery, RouteRecord, RouteRenderResult, RouteRequestOptions, RouteRequestResult, RouteSnapshot } from "../common/router.js";
|
|
2
2
|
|
|
3
3
|
//#region src/router/route.d.ts
|
|
4
4
|
declare function setServerLocation(url: string | null): void;
|
|
5
5
|
declare function _setActiveRouteAuthOptions(auth: RouteAuthOptions | undefined): void;
|
|
6
|
+
/**
|
|
7
|
+
* Prevent route registrations after the app has started.
|
|
8
|
+
* Enforced in production; tests may unlock explicitly.
|
|
9
|
+
*/
|
|
6
10
|
declare function lockRouteRegistration(): void;
|
|
7
11
|
declare function _lockRouteRegistrationForTests(): void;
|
|
8
12
|
declare function _unlockRouteRegistrationForTests(): void;
|
|
13
|
+
declare function Outlet(): unknown;
|
|
9
14
|
/**
|
|
10
15
|
* Snapshot the current in-flight lazy() imports.
|
|
11
16
|
* Boot uses this before clearing route state so manifest-based startup can
|
|
@@ -42,9 +47,13 @@ declare function lazy(factory: () => Promise<{
|
|
|
42
47
|
*/
|
|
43
48
|
declare function _drainLazy(additionalPending?: Iterable<Promise<unknown>>): Promise<void>;
|
|
44
49
|
declare function group(options: GroupHelperOptions, fn: RouteDefinition): void;
|
|
50
|
+
declare function page(path: string, Component: RouteComponent, fn: RouteDefinition): void;
|
|
51
|
+
declare function page(path: string, Component: RouteComponent, options: PageHelperOptions, fn: RouteDefinition): void;
|
|
52
|
+
declare function index(Component: RouteComponent, options?: RouteOptions): void;
|
|
45
53
|
declare function fallback(Component: RouteComponent): void;
|
|
46
54
|
declare function registerRoutes(definition: RouteDefinition, options?: RegisterRoutesOptions): void;
|
|
47
55
|
declare function currentRoute(): RouteSnapshot;
|
|
56
|
+
declare function syncCurrentRouteSnapshot(pathname: string, search: string, hash: string): void;
|
|
48
57
|
/**
|
|
49
58
|
* Register a route.
|
|
50
59
|
*
|
|
@@ -116,5 +125,5 @@ declare function resolveRouteRequest(target: string, options?: RouteRequestOptio
|
|
|
116
125
|
*/
|
|
117
126
|
declare function resolveRouteFromRoutes(pathname: string, routeList: readonly Route[]): ResolvedRoute | null;
|
|
118
127
|
//#endregion
|
|
119
|
-
export { _applyManifest, _drainLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, lazy, registerRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace };
|
|
128
|
+
export { Outlet, _applyManifest, _drainLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, index, lazy, page, registerRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace };
|
|
120
129
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","names":[],"sources":["../../src/router/route.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"route.d.ts","names":[],"sources":["../../src/router/route.ts"],"mappings":";;;iBAoOgB,iBAAA,CAAkB,GAAA;AAAA,iBA8MlB,0BAAA,CACd,IAAA,EAAM,gBAAA;AAuFR;;;;AAAA,iBAJgB,qBAAA,CAAA;AAAA,iBAIA,8BAAA,CAAA;AAAA,iBAIA,gCAAA,CAAA;AAAA,iBAmIA,MAAA,CAAA;;;AAAhB;;;iBASgB,aAAA,CAAA,GAAiB,OAAA;;AAAjC;;;;;AAyBA;;;;;;;;;;;;;;;iBAAgB,IAAA,CACd,OAAA,QAAe,OAAA;EAAU,OAAA,EAAS,cAAA;AAAA,IAAmB,cAAA,IACpD,cAAA;;;;;iBAmCa,UAAA,CACd,iBAAA,GAAmB,QAAA,CAAS,OAAA,aAC3B,OAAA;AAAA,iBASa,KAAA,CAAM,OAAA,EAAS,kBAAA,EAAoB,EAAA,EAAI,eAAA;AAAA,iBAKvC,IAAA,CACd,IAAA,UACA,SAAA,EAAW,cAAA,EACX,EAAA,EAAI,eAAA;AAAA,iBAEU,IAAA,CACd,IAAA,UACA,SAAA,EAAW,cAAA,EACX,OAAA,EAAS,iBAAA,EACT,EAAA,EAAI,eAAA;AAAA,iBA2BU,KAAA,CAAM,SAAA,EAAW,cAAA,EAAgB,OAAA,GAAU,YAAA;AAAA,iBAI3C,QAAA,CAAS,SAAA,EAAW,cAAA;AAAA,iBAkUpB,cAAA,CACd,UAAA,EAAY,eAAA,EACZ,OAAA,GAAS,qBAAA;AAAA,iBAoEK,YAAA,CAAA,GAAgB,aAAA;AAAA,iBAsBhB,wBAAA,CACd,QAAA,UACA,MAAA,UACA,IAAA;AA9cF;;;;;;;;;;AAKA;;AALA,iBA+dgB,KAAA,CACd,IAAA,UACA,SAAA,EAAW,cAAA,EACX,OAAA,GAAU,YAAA;;;;;;;;;AAxdZ;;;iBA0hBgB,WAAA,CAAA,GAAe,aAAA;;;;;iBAWf,cAAA,CAAe,QAAA,EAAU,aAAA;;;;;iBA0BzB,SAAA,CAAA,GAAa,KAAA;;iBAKb,kBAAA,CAAmB,SAAA,WAAoB,KAAA;;iBAKvC,eAAA,CAAgB,SAAA;;iBA6BhB,WAAA,CAAA;;;;iBAiBA,mBAAA,CAAA;;;;AAplBhB;;;;;iBA+nBgB,YAAA,CAAa,QAAA,WAAmB,aAAA;AAAA,iBAuHhC,mBAAA,CACd,MAAA,UACA,OAAA,GAAS,mBAAA,GACR,kBAAA,GAAqB,OAAA,CAAQ,kBAAA;;;;;;;;;AAjXhC;;;;;AAsBA;iBA+ZgB,sBAAA,CACd,QAAA,UACA,SAAA,WAAoB,KAAA,KACnB,aAAA"}
|
package/dist/router/route.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { defineContext, readContext } from "../runtime/context.js";
|
|
2
|
+
import { markReactivePropsDirtySource, markReadableDerivedSubscribersDirty, notifyReadableReaders, recordReadableRead } from "../runtime/readable.js";
|
|
1
3
|
import { getCurrentComponentInstance } from "../runtime/component.js";
|
|
2
4
|
import { computeRank, matchSegments, parseSegments } from "./match.js";
|
|
3
5
|
import { requireAuth, requireGuest, requirePermission, requireRole } from "./policy.js";
|
|
@@ -11,12 +13,14 @@ import { getRenderContext } from "../ssr/context.js";
|
|
|
11
13
|
* Primary public authoring:
|
|
12
14
|
* - `registerRoutes(() => { ... }, options?)`
|
|
13
15
|
* - `group(options, () => { ... })`
|
|
16
|
+
* - `page(path, Component, () => { ... })`
|
|
17
|
+
* - `index(Component, options?)`
|
|
14
18
|
* - `route(path, Component, options?)`
|
|
15
19
|
* - `fallback(Component)`
|
|
20
|
+
* - `Outlet()` for page child rendering
|
|
16
21
|
* - `currentRoute()` for render-time access
|
|
17
22
|
*
|
|
18
23
|
*/
|
|
19
|
-
/** Legacy flat route array — kept for resolver and route() accessor backward compat. */
|
|
20
24
|
const routes = [];
|
|
21
25
|
/** Normalized route records built by the declarative registration API. */
|
|
22
26
|
const records = [];
|
|
@@ -24,6 +28,7 @@ const records = [];
|
|
|
24
28
|
const registrationScopeStack = [];
|
|
25
29
|
const registrationSessionStack = [];
|
|
26
30
|
const namespaces = /* @__PURE__ */ new Set();
|
|
31
|
+
let registrationLocked = false;
|
|
27
32
|
let defaultRouteAuthOptions;
|
|
28
33
|
let activeClientRouteAuthOptions;
|
|
29
34
|
const HAS_ROUTES_KEY = Symbol.for("__ASKR_HAS_ROUTES__");
|
|
@@ -72,6 +77,9 @@ function cachedSortedList(routeList) {
|
|
|
72
77
|
}
|
|
73
78
|
return sorted;
|
|
74
79
|
}
|
|
80
|
+
let currentRouteSnapshot = buildRouteSnapshot("/", "", "");
|
|
81
|
+
const currentRouteSource = (() => currentRouteSnapshot);
|
|
82
|
+
currentRouteSource._readers = /* @__PURE__ */ new Map();
|
|
75
83
|
let serverLocation = null;
|
|
76
84
|
function setServerLocation(url) {
|
|
77
85
|
serverLocation = url;
|
|
@@ -79,27 +87,87 @@ function setServerLocation(url) {
|
|
|
79
87
|
function isPromise(value) {
|
|
80
88
|
return value instanceof Promise;
|
|
81
89
|
}
|
|
90
|
+
function buildRouteSnapshot(pathname, search, hash) {
|
|
91
|
+
const query = makeQuery(search);
|
|
92
|
+
const matches = computeMatchesFromRoutes(pathname, getActiveRoutes());
|
|
93
|
+
return Object.freeze({
|
|
94
|
+
path: pathname,
|
|
95
|
+
params: deepFreeze({ ...matches[0]?.params }),
|
|
96
|
+
query,
|
|
97
|
+
hash: hash || null,
|
|
98
|
+
matches: Object.freeze(matches)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function setCurrentRouteSnapshot(pathname, search, hash) {
|
|
102
|
+
currentRouteSnapshot = buildRouteSnapshot(pathname, search, hash);
|
|
103
|
+
const instance = getCurrentComponentInstance();
|
|
104
|
+
markReadableDerivedSubscribersDirty(currentRouteSource);
|
|
105
|
+
markReactivePropsDirtySource(currentRouteSource);
|
|
106
|
+
notifyReadableReaders(currentRouteSource, instance);
|
|
107
|
+
}
|
|
108
|
+
function matchFallbackPrefix(pathname, fallbackPrefix) {
|
|
109
|
+
const normalizedPath = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
|
|
110
|
+
const normalizedPrefix = fallbackPrefix.endsWith("/") && fallbackPrefix !== "/" ? fallbackPrefix.slice(0, -1) : fallbackPrefix;
|
|
111
|
+
if (normalizedPrefix === "/") {
|
|
112
|
+
const urlParts = normalizedPath === "/" ? [] : normalizedPath.split("/").filter(Boolean);
|
|
113
|
+
return { "*": urlParts.length === 0 ? "/" : urlParts.length === 1 ? urlParts[0] : "/" + urlParts.join("/") };
|
|
114
|
+
}
|
|
115
|
+
if (normalizedPath !== normalizedPrefix && !normalizedPath.startsWith(`${normalizedPrefix}/`)) return null;
|
|
116
|
+
const remainder = normalizedPath === normalizedPrefix ? "/" : normalizedPath.slice(normalizedPrefix.length + 1);
|
|
117
|
+
const remainderParts = remainder === "/" ? [] : remainder.split("/").filter(Boolean);
|
|
118
|
+
return { "*": remainderParts.length === 0 ? "/" : remainderParts.length === 1 ? remainderParts[0] : "/" + remainderParts.join("/") };
|
|
119
|
+
}
|
|
82
120
|
function computeMatchesFromRoutes(pathname, routesList) {
|
|
83
|
-
const
|
|
121
|
+
const bestMatch = routesList === routes ? getMatchingRecord(pathname, records) : findBestResolvedRouteFromRoutes(pathname, routesList);
|
|
122
|
+
if (!bestMatch) return [];
|
|
123
|
+
return [{
|
|
124
|
+
path: "route" in bestMatch ? bestMatch.route.path : bestMatch.record.path,
|
|
125
|
+
params: deepFreeze({ ...bestMatch.params }),
|
|
126
|
+
name: "route" in bestMatch ? bestMatch.route.name : void 0,
|
|
127
|
+
namespace: "route" in bestMatch ? bestMatch.route.namespace : bestMatch.record.options.namespace
|
|
128
|
+
}];
|
|
129
|
+
}
|
|
130
|
+
function findBestResolvedRouteFromRoutes(pathname, routeList) {
|
|
84
131
|
const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
|
|
85
132
|
const urlParts = normalized === "/" ? [] : normalized.split("/").filter(Boolean);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
133
|
+
const sorted = cachedSortedList(routeList);
|
|
134
|
+
let bestRoute = null;
|
|
135
|
+
let bestParams = {};
|
|
136
|
+
let bestRank = -Infinity;
|
|
137
|
+
for (const route of sorted) {
|
|
138
|
+
if (route.fallbackPrefix) continue;
|
|
139
|
+
const rank = cachedRank(route);
|
|
140
|
+
if (rank < bestRank) break;
|
|
141
|
+
if (bestRoute !== null && rank === bestRank) continue;
|
|
142
|
+
const params = matchSegments(urlParts, cachedSegs(route));
|
|
143
|
+
if (params !== null) {
|
|
144
|
+
bestRoute = route;
|
|
145
|
+
bestParams = params;
|
|
146
|
+
bestRank = rank;
|
|
147
|
+
}
|
|
95
148
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
149
|
+
if (bestRoute !== null) return {
|
|
150
|
+
route: bestRoute,
|
|
151
|
+
params: bestParams
|
|
152
|
+
};
|
|
153
|
+
let bestFallback = null;
|
|
154
|
+
let bestFallbackParams = null;
|
|
155
|
+
let bestPrefixLength = -1;
|
|
156
|
+
for (const route of routeList) {
|
|
157
|
+
const internalRoute = route;
|
|
158
|
+
if (!internalRoute.fallbackPrefix) continue;
|
|
159
|
+
const params = matchFallbackPrefix(normalized, internalRoute.fallbackPrefix);
|
|
160
|
+
if (params === null) continue;
|
|
161
|
+
if (internalRoute.fallbackPrefix.length > bestPrefixLength) {
|
|
162
|
+
bestFallback = internalRoute;
|
|
163
|
+
bestFallbackParams = params;
|
|
164
|
+
bestPrefixLength = internalRoute.fallbackPrefix.length;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return bestFallback && bestFallbackParams ? {
|
|
168
|
+
route: bestFallback,
|
|
169
|
+
params: bestFallbackParams
|
|
170
|
+
} : null;
|
|
103
171
|
}
|
|
104
172
|
function getActiveRoutes() {
|
|
105
173
|
return getRenderContext()?.routes ?? routes;
|
|
@@ -125,6 +193,20 @@ function getCurrentLayoutChain() {
|
|
|
125
193
|
for (const scope of registrationScopeStack) if (scope.layout) layoutChain.push({ component: scope.layout });
|
|
126
194
|
return layoutChain;
|
|
127
195
|
}
|
|
196
|
+
function getCurrentPageChain() {
|
|
197
|
+
const pageChain = [];
|
|
198
|
+
for (const scope of registrationScopeStack) if (scope.page) pageChain.push({ component: scope.page });
|
|
199
|
+
return pageChain;
|
|
200
|
+
}
|
|
201
|
+
function hasActivePageScope() {
|
|
202
|
+
return registrationScopeStack.some((scope) => !!scope.page);
|
|
203
|
+
}
|
|
204
|
+
function getCurrentScopeKind() {
|
|
205
|
+
return registrationScopeStack[registrationScopeStack.length - 1]?.kind ?? null;
|
|
206
|
+
}
|
|
207
|
+
function getCurrentPathPrefix() {
|
|
208
|
+
return registrationScopeStack[registrationScopeStack.length - 1]?.pathPrefix ?? "";
|
|
209
|
+
}
|
|
128
210
|
function getCurrentInheritedPolicies() {
|
|
129
211
|
const policies = [];
|
|
130
212
|
for (const scope of registrationScopeStack) if (scope.policies.length > 0) policies.push(...scope.policies);
|
|
@@ -134,7 +216,6 @@ function getCurrentInheritedPolicies() {
|
|
|
134
216
|
* Prevent route registrations after the app has started.
|
|
135
217
|
* Enforced in production; tests may unlock explicitly.
|
|
136
218
|
*/
|
|
137
|
-
let registrationLocked = false;
|
|
138
219
|
function lockRouteRegistration() {
|
|
139
220
|
registrationLocked = true;
|
|
140
221
|
}
|
|
@@ -145,6 +226,37 @@ function validateRoutePath(path) {
|
|
|
145
226
|
throw new Error(`Route parameter syntax uses {name} interpolation, not :name. Use "${suggested}" instead of "${path}".`);
|
|
146
227
|
}
|
|
147
228
|
}
|
|
229
|
+
function normalizeAbsoluteRoutePath(path) {
|
|
230
|
+
if (!path || path === "/") return "/";
|
|
231
|
+
return (path.endsWith("/") ? path.slice(0, -1) : path) || "/";
|
|
232
|
+
}
|
|
233
|
+
function joinRoutePaths(prefix, path) {
|
|
234
|
+
const normalizedPrefix = normalizeAbsoluteRoutePath(prefix || "/");
|
|
235
|
+
const normalizedPath = path.replace(/^\/+|\/+$/g, "");
|
|
236
|
+
if (!normalizedPath) return normalizedPrefix;
|
|
237
|
+
return normalizedPrefix === "/" ? `/${normalizedPath}` : `${normalizedPrefix}/${normalizedPath}`;
|
|
238
|
+
}
|
|
239
|
+
function resolvePageScopePath(path) {
|
|
240
|
+
if (!path) throw new Error("page(path, Component, fn) requires a non-empty path.");
|
|
241
|
+
if (path.startsWith("/")) {
|
|
242
|
+
validateRoutePath(path);
|
|
243
|
+
return normalizeAbsoluteRoutePath(path);
|
|
244
|
+
}
|
|
245
|
+
return joinRoutePaths(getCurrentPathPrefix(), path);
|
|
246
|
+
}
|
|
247
|
+
function resolveIndexPath() {
|
|
248
|
+
return normalizeAbsoluteRoutePath(getCurrentPathPrefix() || "/");
|
|
249
|
+
}
|
|
250
|
+
function resolveRouteRegistrationPath(path) {
|
|
251
|
+
if (path.startsWith("/")) {
|
|
252
|
+
if (hasActivePageScope()) throw new Error(`Child route paths inside page() must be relative. Use "${path.slice(1)}" instead of "${path}".`);
|
|
253
|
+
validateRoutePath(path);
|
|
254
|
+
return normalizeAbsoluteRoutePath(path);
|
|
255
|
+
}
|
|
256
|
+
const prefix = getCurrentPathPrefix();
|
|
257
|
+
if (!prefix) throw new Error(`Route path must begin with "/". Got: "${path}"`);
|
|
258
|
+
return joinRoutePaths(prefix, path);
|
|
259
|
+
}
|
|
148
260
|
function insertRecordSorted(record) {
|
|
149
261
|
let lo = 0;
|
|
150
262
|
let hi = records.length;
|
|
@@ -169,6 +281,10 @@ function addRouteToStores(routeObj) {
|
|
|
169
281
|
}
|
|
170
282
|
/** Promises from in-flight lazy() imports, drained by createSPA / hydrateSPA. */
|
|
171
283
|
const pendingLazy = /* @__PURE__ */ new Set();
|
|
284
|
+
const outletContext = defineContext(null);
|
|
285
|
+
function Outlet() {
|
|
286
|
+
return readContext(outletContext);
|
|
287
|
+
}
|
|
172
288
|
/**
|
|
173
289
|
* Snapshot the current in-flight lazy() imports.
|
|
174
290
|
* Boot uses this before clearing route state so manifest-based startup can
|
|
@@ -227,9 +343,30 @@ function _drainLazy(additionalPending = []) {
|
|
|
227
343
|
function group(options, fn) {
|
|
228
344
|
pushGroupScope(options, fn);
|
|
229
345
|
}
|
|
346
|
+
function page(path, Component, optionsOrFn, maybeFn) {
|
|
347
|
+
const options = typeof optionsOrFn === "function" ? {} : optionsOrFn;
|
|
348
|
+
const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
|
|
349
|
+
if (typeof Component !== "function") throw new Error("page(path, Component, fn) requires a component function as the second argument.");
|
|
350
|
+
if (typeof fn !== "function") throw new Error("page(path, Component, fn) requires a route definition callback as the final argument.");
|
|
351
|
+
pushPageScope(path, Component, options, fn);
|
|
352
|
+
}
|
|
353
|
+
function index(Component, options) {
|
|
354
|
+
registerRouteAtResolvedPath(resolveIndexPath(), Component, options);
|
|
355
|
+
}
|
|
230
356
|
function fallback(Component) {
|
|
357
|
+
if (hasActivePageScope()) {
|
|
358
|
+
if (getCurrentScopeKind() !== "page") throw new Error("fallback() inside page() must be declared directly in the page scope, not inside nested group().");
|
|
359
|
+
registerRouteAtResolvedPath(`${getCurrentPathPrefix()}/*`, Component, void 0, {
|
|
360
|
+
isFallback: true,
|
|
361
|
+
fallbackPrefix: getCurrentPathPrefix()
|
|
362
|
+
});
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
231
365
|
if (!registrationScopeStack.every((scope) => scope.policies.length === 0 && !scope.state.guestOnly && !scope.state.authenticated)) throw new Error("fallback() can only be registered at the root scope. Use route(\"/*\", Component) if you need compatibility behavior.");
|
|
232
|
-
|
|
366
|
+
registerRouteAtResolvedPath("/*", Component, void 0, {
|
|
367
|
+
isFallback: true,
|
|
368
|
+
fallbackPrefix: "/"
|
|
369
|
+
});
|
|
233
370
|
}
|
|
234
371
|
function pushRegistrationScope(scope, fn) {
|
|
235
372
|
registrationScopeStack.push(scope);
|
|
@@ -246,11 +383,28 @@ function pushGroupScope(options, fn) {
|
|
|
246
383
|
});
|
|
247
384
|
const policies = compileNodePolicies(options);
|
|
248
385
|
pushRegistrationScope({
|
|
386
|
+
kind: "group",
|
|
387
|
+
pathPrefix: getCurrentPathPrefix(),
|
|
249
388
|
layout: options.layout,
|
|
250
389
|
policies,
|
|
251
390
|
state: nextAccessScopeState(options, getCurrentAccessScopeState())
|
|
252
391
|
}, fn);
|
|
253
392
|
}
|
|
393
|
+
function pushPageScope(path, Component, options, fn) {
|
|
394
|
+
if (hasActivePageScope()) throw new Error("page() cannot be nested inside another page(). Use route() for child leaves or group() for inherited behavior inside the existing page scope.");
|
|
395
|
+
validateAccessMetadata(options, {
|
|
396
|
+
authConfigured: getCurrentRegistrationSession().authConfigured,
|
|
397
|
+
state: getCurrentAccessScopeState()
|
|
398
|
+
});
|
|
399
|
+
const policies = compileNodePolicies(options);
|
|
400
|
+
pushRegistrationScope({
|
|
401
|
+
kind: "page",
|
|
402
|
+
pathPrefix: resolvePageScopePath(path),
|
|
403
|
+
page: Component,
|
|
404
|
+
policies,
|
|
405
|
+
state: nextAccessScopeState(options, getCurrentAccessScopeState())
|
|
406
|
+
}, fn);
|
|
407
|
+
}
|
|
254
408
|
function hasBuiltInAuthMetadata(node) {
|
|
255
409
|
return node.auth !== void 0 || !!node.role || !!node.permission;
|
|
256
410
|
}
|
|
@@ -297,6 +451,55 @@ function normalizeRouteOptions(options) {
|
|
|
297
451
|
...options.namespace ? { namespace: options.namespace } : {}
|
|
298
452
|
};
|
|
299
453
|
}
|
|
454
|
+
function applyPageChain(pageChain, params, content) {
|
|
455
|
+
let nextContent = content;
|
|
456
|
+
for (let i = pageChain.length - 1; i >= 0; i--) nextContent = outletContext.Scope({
|
|
457
|
+
value: nextContent,
|
|
458
|
+
children: pageChain[i].component(params)
|
|
459
|
+
});
|
|
460
|
+
return nextContent;
|
|
461
|
+
}
|
|
462
|
+
function registerRouteAtResolvedPath(path, Component, options, metadata) {
|
|
463
|
+
validateAccessMetadata(options ?? {}, {
|
|
464
|
+
authConfigured: getCurrentRegistrationSession().authConfigured,
|
|
465
|
+
state: getCurrentAccessScopeState()
|
|
466
|
+
});
|
|
467
|
+
const chain = getCurrentLayoutChain();
|
|
468
|
+
const pageChain = getCurrentPageChain();
|
|
469
|
+
const segments = parseSegments(path);
|
|
470
|
+
const rank = computeRank(segments);
|
|
471
|
+
const isFallback = metadata?.isFallback ?? path === "/*";
|
|
472
|
+
const comp = Component;
|
|
473
|
+
const normalizedOptions = normalizeRouteOptions(options);
|
|
474
|
+
const policies = [...getCurrentInheritedPolicies(), ...normalizedOptions?.policies ?? []];
|
|
475
|
+
const handler = (params) => {
|
|
476
|
+
let content = comp(params);
|
|
477
|
+
content = applyPageChain(pageChain, params, content);
|
|
478
|
+
for (let i = chain.length - 1; i >= 0; i--) content = chain[i].component({ children: content });
|
|
479
|
+
return content;
|
|
480
|
+
};
|
|
481
|
+
insertRecordSorted({
|
|
482
|
+
path,
|
|
483
|
+
component: comp,
|
|
484
|
+
segments,
|
|
485
|
+
rank,
|
|
486
|
+
layoutChain: chain,
|
|
487
|
+
pageChain,
|
|
488
|
+
options: normalizedOptions ? {
|
|
489
|
+
...normalizedOptions,
|
|
490
|
+
...policies.length > 0 ? { policies } : {}
|
|
491
|
+
} : policies.length > 0 ? { policies } : {},
|
|
492
|
+
isFallback,
|
|
493
|
+
handler,
|
|
494
|
+
...metadata?.fallbackPrefix ? { fallbackPrefix: metadata.fallbackPrefix } : {}
|
|
495
|
+
});
|
|
496
|
+
addRouteToStores({
|
|
497
|
+
path,
|
|
498
|
+
handler,
|
|
499
|
+
namespace: normalizedOptions?.namespace ?? options?.namespace,
|
|
500
|
+
...metadata?.fallbackPrefix ? { fallbackPrefix: metadata.fallbackPrefix } : {}
|
|
501
|
+
});
|
|
502
|
+
}
|
|
300
503
|
function registerRoutes(definition, options = {}) {
|
|
301
504
|
defaultRouteAuthOptions = options.auth;
|
|
302
505
|
registrationSessionStack.push({ authConfigured: !!options.auth?.resolve });
|
|
@@ -341,8 +544,19 @@ function readCurrentRouteSnapshot() {
|
|
|
341
544
|
});
|
|
342
545
|
}
|
|
343
546
|
function currentRoute() {
|
|
547
|
+
const instance = getCurrentComponentInstance();
|
|
548
|
+
if (!instance) throw new Error("currentRoute() can only be called during component render execution. Call currentRoute() from inside your component function.");
|
|
549
|
+
if (typeof window === "undefined" || instance.ssr) return readCurrentRouteSnapshot();
|
|
550
|
+
if (currentRouteSnapshot.path !== (window.location.pathname || "/")) {
|
|
551
|
+
recordReadableRead(currentRouteSource);
|
|
552
|
+
return readCurrentRouteSnapshot();
|
|
553
|
+
}
|
|
554
|
+
recordReadableRead(currentRouteSource);
|
|
344
555
|
return readCurrentRouteSnapshot();
|
|
345
556
|
}
|
|
557
|
+
function syncCurrentRouteSnapshot(pathname, search, hash) {
|
|
558
|
+
setCurrentRouteSnapshot(pathname, search, hash);
|
|
559
|
+
}
|
|
346
560
|
function route(path, Component, options) {
|
|
347
561
|
if (getExecutionModel() === "islands") throw new Error("Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead.");
|
|
348
562
|
if (typeof path === "undefined") throw new Error("route() is only for route registration. Use currentRoute() inside components.");
|
|
@@ -350,41 +564,7 @@ function route(path, Component, options) {
|
|
|
350
564
|
if (currentInst && currentInst.ssr) throw new Error("route() cannot be called during SSR rendering. Register routes at module load time instead.");
|
|
351
565
|
if (registrationLocked) throw new Error("Route registration is locked after app startup. Register routes at module load time before calling createSPA or createSSR.");
|
|
352
566
|
if (typeof Component !== "function") throw new Error("route(path, Component) requires a component function as the second argument. Passing JSX elements or VNodes directly is not supported.");
|
|
353
|
-
|
|
354
|
-
validateAccessMetadata(options ?? {}, {
|
|
355
|
-
authConfigured: getCurrentRegistrationSession().authConfigured,
|
|
356
|
-
state: getCurrentAccessScopeState()
|
|
357
|
-
});
|
|
358
|
-
const chain = getCurrentLayoutChain();
|
|
359
|
-
const segments = parseSegments(path);
|
|
360
|
-
const rank = computeRank(segments);
|
|
361
|
-
const isFallback = path === "/*";
|
|
362
|
-
const comp = Component;
|
|
363
|
-
const normalizedOptions = normalizeRouteOptions(options);
|
|
364
|
-
const policies = [...getCurrentInheritedPolicies(), ...normalizedOptions?.policies ?? []];
|
|
365
|
-
const handler = (params) => {
|
|
366
|
-
let content = comp(params);
|
|
367
|
-
for (let i = chain.length - 1; i >= 0; i--) content = chain[i].component({ children: content });
|
|
368
|
-
return content;
|
|
369
|
-
};
|
|
370
|
-
insertRecordSorted({
|
|
371
|
-
path,
|
|
372
|
-
component: comp,
|
|
373
|
-
segments,
|
|
374
|
-
rank,
|
|
375
|
-
layoutChain: chain,
|
|
376
|
-
options: normalizedOptions ? {
|
|
377
|
-
...normalizedOptions,
|
|
378
|
-
...policies.length > 0 ? { policies } : {}
|
|
379
|
-
} : policies.length > 0 ? { policies } : {},
|
|
380
|
-
isFallback,
|
|
381
|
-
handler
|
|
382
|
-
});
|
|
383
|
-
addRouteToStores({
|
|
384
|
-
path,
|
|
385
|
-
handler,
|
|
386
|
-
namespace: normalizedOptions?.namespace ?? options?.namespace
|
|
387
|
-
});
|
|
567
|
+
registerRouteAtResolvedPath(resolveRouteRegistrationPath(path), Component, options);
|
|
388
568
|
}
|
|
389
569
|
/**
|
|
390
570
|
* Return the normalized route manifest built from registered route definitions.
|
|
@@ -410,14 +590,14 @@ function getManifest() {
|
|
|
410
590
|
function _applyManifest(manifest) {
|
|
411
591
|
defaultRouteAuthOptions = manifest.auth;
|
|
412
592
|
for (const record of manifest.records) {
|
|
413
|
-
|
|
593
|
+
insertRecordSorted(record);
|
|
414
594
|
addRouteToStores({
|
|
415
595
|
path: record.path,
|
|
416
596
|
handler: record.handler,
|
|
417
|
-
namespace: record.options.namespace
|
|
597
|
+
namespace: record.options.namespace,
|
|
598
|
+
..."fallbackPrefix" in record && typeof record.fallbackPrefix === "string" ? { fallbackPrefix: record.fallbackPrefix } : {}
|
|
418
599
|
});
|
|
419
600
|
}
|
|
420
|
-
records.sort((a, b) => b.rank - a.rank);
|
|
421
601
|
}
|
|
422
602
|
/**
|
|
423
603
|
* Get all registered routes (flat list, insertion order).
|
|
@@ -467,6 +647,26 @@ function clearRoutes() {
|
|
|
467
647
|
function getLoadedNamespaces() {
|
|
468
648
|
return Array.from(namespaces);
|
|
469
649
|
}
|
|
650
|
+
function findBestScopedFallbackRecord(pathname, routeRecords) {
|
|
651
|
+
let bestRecord = null;
|
|
652
|
+
let bestParams = null;
|
|
653
|
+
let bestPrefixLength = -1;
|
|
654
|
+
for (const routeRecord of routeRecords) {
|
|
655
|
+
const record = routeRecord;
|
|
656
|
+
if (!record.fallbackPrefix) continue;
|
|
657
|
+
const params = matchFallbackPrefix(pathname, record.fallbackPrefix);
|
|
658
|
+
if (params === null) continue;
|
|
659
|
+
if (record.fallbackPrefix.length > bestPrefixLength) {
|
|
660
|
+
bestRecord = record;
|
|
661
|
+
bestParams = params;
|
|
662
|
+
bestPrefixLength = record.fallbackPrefix.length;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return bestRecord && bestParams ? {
|
|
666
|
+
record: bestRecord,
|
|
667
|
+
params: bestParams
|
|
668
|
+
} : null;
|
|
669
|
+
}
|
|
470
670
|
/**
|
|
471
671
|
* Resolve a path to a route handler.
|
|
472
672
|
*
|
|
@@ -479,26 +679,32 @@ function resolveRoute(pathname) {
|
|
|
479
679
|
const normalized = pathname.endsWith("/") && pathname !== "/" ? pathname.slice(0, -1) : pathname;
|
|
480
680
|
const urlParts = normalized === "/" ? [] : normalized.split("/").filter(Boolean);
|
|
481
681
|
for (const record of records) {
|
|
682
|
+
if (record.fallbackPrefix) continue;
|
|
482
683
|
const params = matchSegments(urlParts, record.segments);
|
|
483
684
|
if (params !== null) return {
|
|
484
685
|
handler: record.handler,
|
|
485
686
|
params
|
|
486
687
|
};
|
|
487
688
|
}
|
|
488
|
-
|
|
689
|
+
const fallbackMatch = findBestScopedFallbackRecord(normalized, records);
|
|
690
|
+
return fallbackMatch ? {
|
|
691
|
+
handler: fallbackMatch.record.handler,
|
|
692
|
+
params: fallbackMatch.params
|
|
693
|
+
} : null;
|
|
489
694
|
}
|
|
490
695
|
function getMatchingRecord(target, routeRecords) {
|
|
491
696
|
const location = parseLocation(target);
|
|
492
697
|
const normalized = location.pathname.endsWith("/") && location.pathname !== "/" ? location.pathname.slice(0, -1) : location.pathname;
|
|
493
698
|
const urlParts = normalized === "/" ? [] : normalized.split("/").filter(Boolean);
|
|
494
699
|
for (const record of routeRecords) {
|
|
700
|
+
if (record.fallbackPrefix) continue;
|
|
495
701
|
const params = matchSegments(urlParts, record.segments);
|
|
496
702
|
if (params !== null) return {
|
|
497
703
|
record,
|
|
498
704
|
params
|
|
499
705
|
};
|
|
500
706
|
}
|
|
501
|
-
return
|
|
707
|
+
return findBestScopedFallbackRecord(normalized, routeRecords);
|
|
502
708
|
}
|
|
503
709
|
function getRoutePolicies(options) {
|
|
504
710
|
if (!options) return [];
|
|
@@ -571,29 +777,13 @@ function resolveRouteRequest(target, options = {}) {
|
|
|
571
777
|
*/
|
|
572
778
|
function resolveRouteFromRoutes(pathname, routeList) {
|
|
573
779
|
if (routeList === routes) return resolveRoute(pathname);
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
let bestParams = {};
|
|
579
|
-
let bestRank = -Infinity;
|
|
580
|
-
for (const r of sorted) {
|
|
581
|
-
const rank = cachedRank(r);
|
|
582
|
-
if (rank < bestRank) break;
|
|
583
|
-
if (bestHandler !== null && rank === bestRank) continue;
|
|
584
|
-
const params = matchSegments(urlParts, cachedSegs(r));
|
|
585
|
-
if (params !== null) {
|
|
586
|
-
bestHandler = r.handler;
|
|
587
|
-
bestParams = params;
|
|
588
|
-
bestRank = rank;
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
return bestHandler !== null ? {
|
|
592
|
-
handler: bestHandler,
|
|
593
|
-
params: bestParams
|
|
780
|
+
const match = findBestResolvedRouteFromRoutes(pathname, routeList);
|
|
781
|
+
return match ? {
|
|
782
|
+
handler: match.route.handler,
|
|
783
|
+
params: match.params
|
|
594
784
|
} : null;
|
|
595
785
|
}
|
|
596
786
|
//#endregion
|
|
597
|
-
export { _applyManifest, _drainLazy, _setActiveRouteAuthOptions, _snapshotLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, lazy, lockRouteRegistration, registerRoutes, resolveRoute, resolveRouteFromRoutes, resolveRouteRequest, route, setServerLocation, unloadNamespace };
|
|
787
|
+
export { Outlet, _applyManifest, _drainLazy, _setActiveRouteAuthOptions, _snapshotLazy, clearRoutes, currentRoute, fallback, getLoadedNamespaces, getManifest, getNamespaceRoutes, getRoutes, group, index, lazy, lockRouteRegistration, page, registerRoutes, resolveRoute, resolveRouteFromRoutes, resolveRouteRequest, route, setServerLocation, syncCurrentRouteSnapshot, unloadNamespace };
|
|
598
788
|
|
|
599
789
|
//# sourceMappingURL=route.js.map
|
package/dist/router/route.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","names":[],"sources":["../../src/router/route.ts"],"sourcesContent":["/**\n * Route definition, registration, and matching.\n *\n * Primary public authoring:\n * - `registerRoutes(() => { ... }, options?)`\n * - `group(options, () => { ... })`\n * - `route(path, Component, options?)`\n * - `fallback(Component)`\n * - `currentRoute()` for render-time access\n *\n */\n\nimport { matchSegments, parseSegments, computeRank } from './match';\nimport {\n buildRouteContext,\n buildRouteContextBase,\n deepFreeze,\n makeQuery,\n parseLocation,\n} from './route-context';\nimport { getCurrentComponentInstance } from '../runtime/component';\nimport { getExecutionModel } from '../runtime/execution-model';\nimport { getRenderContext } from '../ssr/context';\nimport {\n requireAuth,\n requireGuest,\n requirePermission,\n requireRole,\n} from './policy';\n\nexport type {\n AccessDecision,\n AccessDenyDecision,\n AccessRedirectDecision,\n GroupHelperOptions,\n RegisterRoutesOptions,\n RouteDefinition,\n RouteAuthOptions,\n RouteHandler,\n Route,\n RouteContext,\n RoutePolicy,\n RouteRenderResult,\n RouteRequestOptions,\n RouteRequestResult,\n ResolvedRoute,\n RouteMatch,\n RouteQuery,\n RouteSnapshot,\n RouteComponent,\n RouteOptions,\n ParsedSegment,\n LayoutScopeRecord,\n RouteRecord,\n RouteManifest,\n} from '../common/router';\n\nimport type {\n AccessDecision,\n AccessDenyDecision,\n AccessRedirectDecision,\n GroupHelperOptions,\n RegisterRoutesOptions,\n RouteDefinition,\n RouteAuthOptions,\n RouteHandler,\n Route,\n RouteContext,\n RoutePolicy,\n RouteRenderResult,\n RouteRequestOptions,\n RouteRequestResult,\n ResolvedRoute,\n RouteMatch,\n RouteQuery,\n RouteSnapshot,\n RouteComponent,\n RouteOptions,\n LayoutScopeRecord,\n RouteRecord,\n RouteManifest,\n} from '../common/router';\n\n// ---------------------------------------------------------------------------\n// Module-level stores\n// ---------------------------------------------------------------------------\n\n/** Legacy flat route array — kept for resolver and route() accessor backward compat. */\nconst routes: Route[] = [];\n\n/** Normalized route records built by the declarative registration API. */\nconst records: RouteRecord[] = [];\n\ntype RegistrationScope = {\n layout?: LayoutScopeRecord['component'];\n policies: readonly RoutePolicy[];\n state: AccessScopeState;\n};\n\ntype RegistrationSession = {\n authConfigured: boolean;\n};\n\n/** Active registration scope stack during module-load-time registration. */\nconst registrationScopeStack: RegistrationScope[] = [];\nconst registrationSessionStack: RegistrationSession[] = [];\n\nconst namespaces = new Set<string>();\n\ntype AccessScopeState = {\n guestOnly: boolean;\n authenticated: boolean;\n};\n\nlet defaultRouteAuthOptions: RouteAuthOptions | undefined;\nlet activeClientRouteAuthOptions: RouteAuthOptions | undefined;\n\nconst HAS_ROUTES_KEY = Symbol.for('__ASKR_HAS_ROUTES__');\n\nfunction setHasRoutes(value: boolean): void {\n try {\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n g[HAS_ROUTES_KEY] = value;\n } catch {\n // ignore\n }\n}\n\n// Initialize to false at module load.\nsetHasRoutes(false);\n\n// Route index by depth - maintains insertion order\nconst routesByDepth = new Map<number, Route[]>();\n\n/**\n * Parse route path depth\n */\nfunction getDepth(path: string): number {\n const normalized =\n path.endsWith('/') && path !== '/' ? path.slice(0, -1) : path;\n return normalized === '/' ? 0 : normalized.split('/').filter(Boolean).length;\n}\n\n// ---------------------------------------------------------------------------\n// WeakMap caches for external Route[] objects (e.g. SSR per-request tables)\n// Amortises parseSegments / computeRank across repeated resolveRouteFromRoutes\n// calls on the same route list (same object reference).\n// ---------------------------------------------------------------------------\n\n/** Pre-parsed segments for an externally supplied Route object. */\nconst routeSegsCache = new WeakMap<Route, ReturnType<typeof parseSegments>>();\n/** Pre-computed rank for an externally supplied Route object. */\nconst routeRankCache = new WeakMap<Route, number>();\n/** A rank-descending sorted copy of an external readonly Route array. */\nconst sortedListCache = new WeakMap<\n ReadonlyArray<Route>,\n ReadonlyArray<Route>\n>();\n\nfunction cachedSegs(r: Route): ReturnType<typeof parseSegments> {\n let s = routeSegsCache.get(r);\n if (!s) {\n s = parseSegments(r.path);\n routeSegsCache.set(r, s);\n }\n return s;\n}\n\nfunction cachedRank(r: Route): number {\n let n = routeRankCache.get(r);\n if (n === undefined) {\n n = computeRank(cachedSegs(r));\n routeRankCache.set(r, n);\n }\n return n;\n}\n\nfunction cachedSortedList(\n routeList: ReadonlyArray<Route>\n): ReadonlyArray<Route> {\n let sorted = sortedListCache.get(routeList);\n if (!sorted) {\n sorted = [...routeList].sort((a, b) => cachedRank(b) - cachedRank(a));\n sortedListCache.set(routeList, sorted);\n }\n return sorted;\n}\n\n// SSR helper: when rendering on the server, callers may set a location so that\n// render-time route() returns deterministic server values that match client\n// hydration. This is deliberately an opt-in escape for SSR and tests.\nlet serverLocation: string | null = null;\n\nexport function setServerLocation(url: string | null): void {\n serverLocation = url;\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return value instanceof Promise;\n}\n\n// Compute matches for a specific route list.\nfunction computeMatchesFromRoutes(\n pathname: string,\n routesList: readonly Route[]\n): RouteMatch[] {\n const matches: Array<{\n pattern: string;\n params: Record<string, string>;\n name?: string;\n namespace?: string;\n rank: number;\n }> = [];\n\n const normalized =\n pathname.endsWith('/') && pathname !== '/'\n ? pathname.slice(0, -1)\n : pathname;\n const urlParts =\n normalized === '/' ? [] : normalized.split('/').filter(Boolean);\n\n for (const r of routesList) {\n const params = matchSegments(urlParts, cachedSegs(r));\n if (params !== null) {\n matches.push({\n pattern: r.path,\n params,\n name: (r as { name?: string }).name,\n namespace: r.namespace,\n rank: cachedRank(r),\n });\n }\n }\n\n matches.sort((a, b) => b.rank - a.rank);\n\n return matches.map((m) => ({\n path: m.pattern,\n params: deepFreeze({ ...m.params }),\n name: m.name,\n namespace: m.namespace,\n }));\n}\n\nfunction getActiveRoutes(): readonly Route[] {\n const renderContext = getRenderContext();\n return renderContext?.routes ?? routes;\n}\n\nfunction getActiveRouteAuthOptions(\n override?: RouteAuthOptions\n): RouteAuthOptions | undefined {\n if (override) {\n return override;\n }\n\n const renderContext = getRenderContext();\n return (\n renderContext?.routeAuth ??\n activeClientRouteAuthOptions ??\n defaultRouteAuthOptions\n );\n}\n\nexport function _setActiveRouteAuthOptions(\n auth: RouteAuthOptions | undefined\n): void {\n activeClientRouteAuthOptions = auth;\n}\n\nfunction getCurrentRegistrationSession(): RegistrationSession {\n return (\n registrationSessionStack[registrationSessionStack.length - 1] ?? {\n authConfigured: !!defaultRouteAuthOptions?.resolve,\n }\n );\n}\n\nfunction getCurrentAccessScopeState(): AccessScopeState {\n return (\n registrationScopeStack[registrationScopeStack.length - 1]?.state ?? {\n guestOnly: false,\n authenticated: false,\n }\n );\n}\n\nfunction getCurrentLayoutChain(): LayoutScopeRecord[] {\n const layoutChain: LayoutScopeRecord[] = [];\n\n for (const scope of registrationScopeStack) {\n if (scope.layout) {\n layoutChain.push({ component: scope.layout });\n }\n }\n\n return layoutChain;\n}\n\nfunction getCurrentInheritedPolicies(): RoutePolicy[] {\n const policies: RoutePolicy[] = [];\n\n for (const scope of registrationScopeStack) {\n if (scope.policies.length > 0) {\n policies.push(...scope.policies);\n }\n }\n\n return policies;\n}\n\n// ---------------------------------------------------------------------------\n// Registration lock\n// ---------------------------------------------------------------------------\n\n/**\n * Prevent route registrations after the app has started.\n * Enforced in production; tests may unlock explicitly.\n */\nlet registrationLocked = false;\n\nexport function lockRouteRegistration(): void {\n registrationLocked = true;\n}\n\nexport function _lockRouteRegistrationForTests(): void {\n registrationLocked = true;\n}\n\nexport function _unlockRouteRegistrationForTests(): void {\n registrationLocked = false;\n}\n\n// ---------------------------------------------------------------------------\n// Path validation\n// ---------------------------------------------------------------------------\n\nfunction validateRoutePath(path: string): void {\n if (!path.startsWith('/')) {\n throw new Error(`Route path must begin with \"/\". Got: \"${path}\"`);\n }\n // Reject Express-style :param syntax — Askr uses {param} interpolation\n if (/:([^/{}]+)/.test(path)) {\n const suggested = path.replace(/:([^/{}]+)/g, '{$1}');\n throw new Error(\n `Route parameter syntax uses {name} interpolation, not :name. ` +\n `Use \"${suggested}\" instead of \"${path}\".`\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: insert a RouteRecord in rank-descending order\n// so that resolveRoute can use first-match-wins without sorting.\n// Ties preserve declaration order (stable binary-search insertion).\n// ---------------------------------------------------------------------------\n\nfunction insertRecordSorted(record: RouteRecord): void {\n let lo = 0;\n let hi = records.length;\n // Find the insertion point: after all existing records with rank >= this one\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (records[mid].rank >= record.rank) lo = mid + 1;\n else hi = mid;\n }\n records.splice(lo, 0, record);\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: add a single pre-built Route object to the runtime stores\n// ---------------------------------------------------------------------------\n\nfunction addRouteToStores(routeObj: Route): void {\n routes.push(routeObj);\n setHasRoutes(true);\n\n const depth = getDepth(routeObj.path);\n let depthRoutes = routesByDepth.get(depth);\n if (!depthRoutes) {\n depthRoutes = [];\n routesByDepth.set(depth, depthRoutes);\n }\n depthRoutes.push(routeObj);\n\n if (routeObj.namespace) {\n namespaces.add(routeObj.namespace);\n }\n}\n\n// ---------------------------------------------------------------------------\n// lazy() — eager-prefetch code-split component wrapper\n// ---------------------------------------------------------------------------\n\n/** Promises from in-flight lazy() imports, drained by createSPA / hydrateSPA. */\nconst pendingLazy = new Set<Promise<unknown>>();\n\n/**\n * Snapshot the current in-flight lazy() imports.\n * Boot uses this before clearing route state so manifest-based startup can\n * still await chunks that were kicked off during route module evaluation.\n */\nexport function _snapshotLazy(): Promise<unknown>[] {\n return [...pendingLazy];\n}\n\n/**\n * Declare a code-split route component. The `import()` fires immediately at\n * module evaluation time (creating a bundler split point), and the resolved\n * chunk is guaranteed to be available before the app mounts — so the renderer\n * always receives a plain synchronous function.\n *\n * ```ts\n * registerRoutes(() => {\n * group({ layout: AppLayout }, () => {\n * route('/', lazy(() => import('./pages/landing')));\n * route('/dashboard', lazy(() => import('./pages/dashboard')));\n * });\n * });\n * ```\n *\n * The module must export the component as its **default** export:\n * ```ts\n * // pages/dashboard.tsx\n * export default function DashboardPage() { … }\n * ```\n */\nexport function lazy(\n factory: () => Promise<{ default: RouteComponent } | RouteComponent>\n): RouteComponent {\n let resolved: RouteComponent | null = null;\n let loadError: unknown = null;\n\n const promise = factory().then(\n (mod) => {\n resolved =\n typeof mod === 'function'\n ? mod\n : (mod as { default: RouteComponent }).default;\n pendingLazy.delete(promise);\n },\n (err: unknown) => {\n loadError = err;\n pendingLazy.delete(promise);\n }\n );\n pendingLazy.add(promise);\n\n return (params) => {\n if (loadError) throw loadError as Error;\n if (!resolved) {\n throw new Error(\n 'lazy() component used before it was resolved. ' +\n 'Await createSPA() / hydrateSPA() to ensure all chunks load first.'\n );\n }\n return resolved(params);\n };\n}\n\n/**\n * Wait for all pending `lazy()` imports to settle.\n * Called automatically by `createSPA` / `hydrateSPA` before mounting.\n */\nexport function _drainLazy(\n additionalPending: Iterable<Promise<unknown>> = []\n): Promise<void> {\n const combined = new Set<Promise<unknown>>([\n ...additionalPending,\n ...pendingLazy,\n ]);\n if (combined.size === 0) return Promise.resolve();\n return Promise.allSettled(combined).then(() => undefined);\n}\n\nexport function group(options: GroupHelperOptions, fn: RouteDefinition): void;\nexport function group(options: GroupHelperOptions, fn: RouteDefinition): void {\n pushGroupScope(options, fn);\n}\n\nexport function fallback(Component: RouteComponent): void {\n const allowsRootFallback = registrationScopeStack.every(\n (scope) =>\n scope.policies.length === 0 &&\n !scope.state.guestOnly &&\n !scope.state.authenticated\n );\n\n if (!allowsRootFallback) {\n throw new Error(\n 'fallback() can only be registered at the root scope. ' +\n 'Use route(\"/*\", Component) if you need compatibility behavior.'\n );\n }\n\n route('/*', Component);\n}\n\nfunction pushRegistrationScope(\n scope: RegistrationScope,\n fn: RouteDefinition\n): void {\n registrationScopeStack.push(scope);\n try {\n fn();\n } finally {\n registrationScopeStack.pop();\n }\n}\n\nfunction pushGroupScope(\n options: GroupHelperOptions,\n fn: RouteDefinition\n): void {\n const session = getCurrentRegistrationSession();\n validateAccessMetadata(options, {\n authConfigured: session.authConfigured,\n state: getCurrentAccessScopeState(),\n });\n const policies = compileNodePolicies(options);\n\n pushRegistrationScope(\n {\n layout: options.layout,\n policies,\n state: nextAccessScopeState(options, getCurrentAccessScopeState()),\n },\n fn\n );\n}\n\nfunction hasBuiltInAuthMetadata(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>\n): boolean {\n return node.auth !== undefined || !!node.role || !!node.permission;\n}\n\nfunction validateSameNodeAccessMetadata(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>\n): void {\n if (node.auth === 'guest' && (!!node.role || !!node.permission)) {\n throw new Error(\n 'Guest-only routes cannot be combined with role or permission requirements.'\n );\n }\n}\n\nfunction validateAccessMetadata(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>,\n context: {\n authConfigured: boolean;\n state: AccessScopeState;\n }\n): void {\n validateSameNodeAccessMetadata(node);\n\n const requiresAuthenticated =\n node.auth === true || !!node.role || !!node.permission;\n\n if (\n node.auth === 'guest' &&\n (context.state.authenticated || !!node.role || !!node.permission)\n ) {\n throw new Error(\n 'Guest-only routes cannot be combined with authenticated access requirements.'\n );\n }\n\n if (context.state.guestOnly && requiresAuthenticated) {\n throw new Error(\n 'Child routes cannot weaken a guest-only access scope with authenticated requirements.'\n );\n }\n\n if (hasBuiltInAuthMetadata(node) && !context.authConfigured) {\n throw new Error(\n 'Routes using `auth`, `role`, or `permission` require `auth.resolve` in registerRoutes(...).'\n );\n }\n}\n\nfunction nextAccessScopeState(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>,\n state: AccessScopeState\n): AccessScopeState {\n const requiresAuthenticated =\n node.auth === true || !!node.role || !!node.permission;\n\n return {\n guestOnly: state.guestOnly || node.auth === 'guest',\n authenticated: state.authenticated || requiresAuthenticated,\n };\n}\n\nfunction compileNodePolicies(\n node: Pick<\n RouteOptions | GroupHelperOptions,\n 'auth' | 'role' | 'permission' | 'policies'\n >\n): RoutePolicy[] {\n validateSameNodeAccessMetadata(node);\n\n const compiled: RoutePolicy[] = [];\n\n if (node.auth === true) {\n compiled.push(requireAuth());\n } else if (node.auth === 'guest') {\n compiled.push(requireGuest());\n }\n\n if (node.role) {\n compiled.push(requireRole(node.role));\n }\n\n if (node.permission) {\n compiled.push(requirePermission(node.permission));\n }\n\n if (node.policies?.length) {\n compiled.push(...node.policies);\n }\n\n return compiled;\n}\n\nfunction normalizeRouteOptions(\n options: RouteOptions | undefined\n): RouteOptions | undefined {\n if (!options) {\n return undefined;\n }\n\n const loader = options.loader;\n const policies = compileNodePolicies(options);\n\n if (\n !loader &&\n !options.entries &&\n policies.length === 0 &&\n !options.title &&\n !options.namespace &&\n options.auth === undefined &&\n !options.role &&\n !options.permission\n ) {\n return undefined;\n }\n\n return {\n ...(loader ? { loader } : {}),\n ...(options.entries ? { entries: options.entries } : {}),\n ...(options.auth !== undefined ? { auth: options.auth } : {}),\n ...(options.role ? { role: options.role } : {}),\n ...(options.permission ? { permission: options.permission } : {}),\n ...(policies.length > 0 ? { policies } : {}),\n ...(options.title ? { title: options.title } : {}),\n ...(options.namespace ? { namespace: options.namespace } : {}),\n };\n}\nexport function registerRoutes(\n definition: RouteDefinition,\n options: RegisterRoutesOptions = {}\n): void {\n defaultRouteAuthOptions = options.auth;\n\n registrationSessionStack.push({\n authConfigured: !!options.auth?.resolve,\n });\n try {\n definition();\n } finally {\n registrationSessionStack.pop();\n }\n}\n\n// ---------------------------------------------------------------------------\n// route() — dual-purpose: registration (module load) + accessor (render time)\n// ---------------------------------------------------------------------------\n\nfunction readCurrentRouteSnapshot(): RouteSnapshot {\n const instance = getCurrentComponentInstance();\n if (!instance) {\n throw new Error(\n 'currentRoute() can only be called during component render execution. ' +\n 'Call currentRoute() from inside your component function.'\n );\n }\n\n let pathname = '/';\n let search = '';\n let hash = '';\n const renderContext = getRenderContext();\n\n if (instance.ssr && renderContext?.url) {\n const parsed = parseLocation(renderContext.url);\n pathname = parsed.pathname;\n search = parsed.search;\n hash = parsed.hash;\n } else if (typeof window !== 'undefined' && window.location) {\n pathname = window.location.pathname || '/';\n search = window.location.search || '';\n hash = window.location.hash || '';\n } else if (serverLocation) {\n const parsed = parseLocation(serverLocation);\n pathname = parsed.pathname;\n search = parsed.search;\n hash = parsed.hash;\n }\n\n const query = makeQuery(search);\n const matches = computeMatchesFromRoutes(pathname, getActiveRoutes());\n const instanceParams = instance.props as Record<string, string>;\n const routeParams =\n Object.keys(instanceParams).length > 0\n ? instanceParams\n : (matches[0]?.params ?? {});\n const params = deepFreeze({\n ...routeParams,\n });\n\n return Object.freeze({\n path: pathname,\n params,\n query,\n hash: hash || null,\n matches: Object.freeze(matches),\n });\n}\n\nexport function currentRoute(): RouteSnapshot {\n return readCurrentRouteSnapshot();\n}\n\n/**\n * Register a route.\n *\n * ```ts\n * route('/posts/{slug}', PostPage, {\n * loader: ({ params }) => getPost(params.slug),\n * entries: async () => getPosts().map(p => ({ slug: p.slug })),\n * title: 'Post',\n * policies:[requireAuth()],\n * });\n * ```\n */\nexport function route(\n path: string,\n Component: RouteComponent,\n options?: RouteOptions\n): void;\nexport function route(\n path: string,\n Component: RouteComponent,\n options?: RouteOptions\n): void {\n if (getExecutionModel() === 'islands') {\n throw new Error(\n 'Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead.'\n );\n }\n\n // ── Render-time accessor (no arguments) ─────────────────────────────────\n if (typeof path === 'undefined') {\n throw new Error(\n 'route() is only for route registration. Use currentRoute() inside components.'\n );\n }\n\n // ── Registration mode ────────────────────────────────────────────────────\n\n // Disallow registration during SSR render\n const currentInst = getCurrentComponentInstance();\n if (currentInst && currentInst.ssr) {\n throw new Error(\n 'route() cannot be called during SSR rendering. Register routes at module load time instead.'\n );\n }\n\n if (registrationLocked) {\n throw new Error(\n 'Route registration is locked after app startup. ' +\n 'Register routes at module load time before calling createSPA or createSSR.'\n );\n }\n\n if (typeof Component !== 'function') {\n throw new Error(\n 'route(path, Component) requires a component function as the second argument. ' +\n 'Passing JSX elements or VNodes directly is not supported.'\n );\n }\n\n validateRoutePath(path);\n validateAccessMetadata(options ?? {}, {\n authConfigured: getCurrentRegistrationSession().authConfigured,\n state: getCurrentAccessScopeState(),\n });\n\n const chain = getCurrentLayoutChain();\n const segments = parseSegments(path);\n const rank = computeRank(segments);\n const isFallback = path === '/*';\n const comp = Component;\n const normalizedOptions = normalizeRouteOptions(options);\n const policies = [\n ...getCurrentInheritedPolicies(),\n ...(normalizedOptions?.policies ?? []),\n ];\n\n const handler: RouteHandler = (params) => {\n let content = comp(params);\n\n for (let i = chain.length - 1; i >= 0; i--) {\n content = chain[i].component({ children: content });\n }\n\n return content;\n };\n\n const record: RouteRecord = {\n path,\n component: comp,\n segments,\n rank,\n layoutChain: chain,\n options: normalizedOptions\n ? {\n ...normalizedOptions,\n ...(policies.length > 0 ? { policies } : {}),\n }\n : policies.length > 0\n ? { policies }\n : {},\n isFallback,\n handler,\n };\n\n insertRecordSorted(record);\n addRouteToStores({\n path,\n handler,\n namespace: normalizedOptions?.namespace ?? options?.namespace,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Manifest access\n// ---------------------------------------------------------------------------\n\n/**\n * Return the normalized route manifest built from registered route definitions.\n *\n * Pass this to `createSPA`, `hydrateSPA`, or `renderToString` as the\n * authoritative routing input:\n *\n * ```ts\n * import { getManifest } from '@askrjs/askr/router';\n * await createSPA({ root: '#app', manifest: getManifest() });\n * ```\n */\nexport function getManifest(): RouteManifest {\n return {\n records: [...records],\n ...(defaultRouteAuthOptions ? { auth: defaultRouteAuthOptions } : {}),\n };\n}\n\n/**\n * Internal: apply a pre-built manifest to the runtime stores without running\n * route() again. Called by createSPA / hydrateSPA when a manifest is passed.\n */\nexport function _applyManifest(manifest: RouteManifest): void {\n defaultRouteAuthOptions = manifest.auth;\n for (const record of manifest.records) {\n records.push(record);\n addRouteToStores({\n path: record.path,\n handler: record.handler,\n namespace: record.options.namespace,\n });\n }\n // Sort once after bulk insert so resolveRoute can use first-match-wins\n records.sort((a, b) => b.rank - a.rank);\n}\n\n// ---------------------------------------------------------------------------\n// Route collection helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Get all registered routes (flat list, insertion order).\n * Prefer `getManifest()` when metadata (loader, policies, entries) is needed.\n */\nexport function getRoutes(): Route[] {\n return [...routes];\n}\n\n/** Get routes for a specific namespace. */\nexport function getNamespaceRoutes(namespace: string): Route[] {\n return routes.filter((r) => r.namespace === namespace);\n}\n\n/** Unload all routes from a namespace (for MFE unmounting). */\nexport function unloadNamespace(namespace: string): number {\n const before = routes.length;\n\n for (let i = routes.length - 1; i >= 0; i--) {\n if (routes[i].namespace === namespace) {\n const removed = routes[i];\n routes.splice(i, 1);\n\n const depth = getDepth(removed.path);\n const depthRoutes = routesByDepth.get(depth);\n if (depthRoutes) {\n const idx = depthRoutes.indexOf(removed);\n if (idx >= 0) depthRoutes.splice(idx, 1);\n }\n }\n }\n\n // Remove matching records too\n for (let i = records.length - 1; i >= 0; i--) {\n if (records[i].options.namespace === namespace) {\n records.splice(i, 1);\n }\n }\n\n namespaces.delete(namespace);\n return before - routes.length;\n}\n\n/** Clear all registered routes and records (testing / boot reset). */\nexport function clearRoutes(): void {\n routes.length = 0;\n records.length = 0;\n namespaces.clear();\n routesByDepth.clear();\n registrationScopeStack.length = 0;\n registrationSessionStack.length = 0;\n registrationLocked = false;\n defaultRouteAuthOptions = undefined;\n activeClientRouteAuthOptions = undefined;\n setHasRoutes(false);\n pendingLazy.clear();\n}\n\n/**\n * Get all loaded namespaces (MFE identifiers)\n */\nexport function getLoadedNamespaces(): string[] {\n return Array.from(namespaces);\n}\n\n/**\n * Resolve a path to a route handler.\n *\n * Hot path: walks the module-level `records[]` array which is kept sorted by\n * rank descending at registration time — so the first `matchSegments` hit is\n * always the most specific match. No per-call allocations for the common\n * case of purely-static routes.\n */\nexport function resolveRoute(pathname: string): ResolvedRoute | null {\n const normalized =\n pathname.endsWith('/') && pathname !== '/'\n ? pathname.slice(0, -1)\n : pathname;\n const urlParts =\n normalized === '/' ? [] : normalized.split('/').filter(Boolean);\n\n for (const record of records) {\n const params = matchSegments(urlParts, record.segments);\n if (params !== null) {\n return { handler: record.handler, params };\n }\n }\n return null;\n}\n\nfunction getMatchingRecord(\n target: string,\n routeRecords: readonly RouteRecord[]\n): { record: RouteRecord; params: Record<string, string> } | null {\n const location = parseLocation(target);\n const normalized =\n location.pathname.endsWith('/') && location.pathname !== '/'\n ? location.pathname.slice(0, -1)\n : location.pathname;\n const urlParts =\n normalized === '/' ? [] : normalized.split('/').filter(Boolean);\n\n for (const record of routeRecords) {\n const params = matchSegments(urlParts, record.segments);\n if (params !== null) {\n return { record, params };\n }\n }\n\n return null;\n}\n\nfunction getRoutePolicies(\n options: RouteOptions | undefined\n): readonly RoutePolicy[] {\n if (!options) {\n return [];\n }\n\n if (options.policies?.length) {\n return options.policies;\n }\n\n return compileNodePolicies(options);\n}\n\nfunction getDefaultRouteMode(): RouteContext['mode'] {\n if (typeof window !== 'undefined') {\n return 'spa';\n }\n\n return 'ssr';\n}\n\nfunction buildRenderResult(\n record: RouteRecord,\n params: Record<string, string>\n): RouteRenderResult {\n return {\n kind: 'render',\n handler: record.handler,\n params,\n };\n}\n\nfunction continueRoutePolicies(\n policies: readonly RoutePolicy[],\n context: RouteContext,\n record: RouteRecord,\n params: Record<string, string>,\n startIndex = 0\n): RouteRequestResult | Promise<RouteRequestResult> {\n for (let index = startIndex; index < policies.length; index += 1) {\n const policyResult = policies[index](context);\n\n if (isPromise(policyResult)) {\n return policyResult.then((next) => {\n if (next.kind !== 'allow') {\n return next;\n }\n\n return continueRoutePolicies(\n policies,\n context,\n record,\n params,\n index + 1\n );\n });\n }\n\n if (policyResult.kind !== 'allow') {\n return policyResult;\n }\n }\n\n return buildRenderResult(record, params);\n}\n\nexport function resolveRouteRequest(\n target: string,\n options: RouteRequestOptions = {}\n): RouteRequestResult | Promise<RouteRequestResult> {\n const routeRecords = options.manifest?.records ?? records;\n const match = getMatchingRecord(target, routeRecords);\n\n if (!match) {\n return null;\n }\n\n const { record, params } = match;\n const policies = getRoutePolicies(record.options);\n\n if (policies.length === 0) {\n return buildRenderResult(record, params);\n }\n\n const signal =\n options.signal ??\n getRenderContext()?.signal ??\n new AbortController().signal;\n const mode = options.mode ?? getDefaultRouteMode();\n const auth = getActiveRouteAuthOptions(\n options.auth ?? options.manifest?.auth\n );\n const baseContext = buildRouteContextBase(target, params, {\n mode,\n signal,\n });\n\n const finalize = (authState: { session: unknown; user: unknown }) =>\n continueRoutePolicies(\n policies,\n buildRouteContext(target, params, {\n mode,\n signal,\n auth,\n session: authState.session,\n user: authState.user,\n }),\n record,\n params\n );\n\n if (!auth?.resolve) {\n return finalize({ session: null, user: null });\n }\n\n const authState = auth.resolve(baseContext);\n if (isPromise(authState)) {\n return authState.then((next) => finalize(next));\n }\n\n return finalize(authState);\n}\n\n/**\n * Resolve a path against an explicit route list (e.g. an SSR per-render\n * context). When called with the global `routes` array this delegates to\n * the faster `resolveRoute` which uses pre-sorted `records[]`.\n *\n * For externally supplied lists the function:\n * 1. Builds a rank-sorted copy of the list on first call and caches it\n * in a WeakMap so subsequent resolutions against the same list pay\n * zero sort cost.\n * 2. Uses pre-parsed `ParsedSegment[]` from a WeakMap cache so no string\n * splitting or segment parsing occurs on the hot path.\n * 3. Uses a running-best with an early-exit once the sorted list reaches\n * a rank that cannot beat the current best match.\n */\nexport function resolveRouteFromRoutes(\n pathname: string,\n routeList: readonly Route[]\n): ResolvedRoute | null {\n if (routeList === routes) return resolveRoute(pathname);\n\n const normalized =\n pathname.endsWith('/') && pathname !== '/'\n ? pathname.slice(0, -1)\n : pathname;\n const urlParts =\n normalized === '/' ? [] : normalized.split('/').filter(Boolean);\n\n // Use the rank-sorted cached copy so we can exit as soon as the rank\n // drops below the current best — typically saving 30-50% of iterations.\n const sorted = cachedSortedList(routeList);\n let bestHandler: RouteHandler | null = null;\n let bestParams: Record<string, string> = {};\n let bestRank = -Infinity;\n\n for (const r of sorted) {\n const rank = cachedRank(r);\n // sorted descending: once rank < bestRank every remaining route loses\n if (rank < bestRank) break;\n // already have the best match at this rank (first-declared wins)\n if (bestHandler !== null && rank === bestRank) continue;\n const params = matchSegments(urlParts, cachedSegs(r));\n if (params !== null) {\n bestHandler = r.handler;\n bestParams = params;\n bestRank = rank;\n }\n }\n\n return bestHandler !== null\n ? { handler: bestHandler, params: bestParams }\n : null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"route.js","names":[],"sources":["../../src/router/route.ts"],"sourcesContent":["/**\n * Route definition, registration, and matching.\n *\n * Primary public authoring:\n * - `registerRoutes(() => { ... }, options?)`\n * - `group(options, () => { ... })`\n * - `page(path, Component, () => { ... })`\n * - `index(Component, options?)`\n * - `route(path, Component, options?)`\n * - `fallback(Component)`\n * - `Outlet()` for page child rendering\n * - `currentRoute()` for render-time access\n *\n */\n\nimport { matchSegments, parseSegments, computeRank } from './match';\nimport {\n buildRouteContext,\n buildRouteContextBase,\n deepFreeze,\n makeQuery,\n parseLocation,\n} from './route-context';\nimport { defineContext, readContext } from '../runtime/context';\nimport { getCurrentComponentInstance } from '../runtime/component';\nimport { getExecutionModel } from '../runtime/execution-model';\nimport {\n markReadableDerivedSubscribersDirty,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n type ReadableSource,\n} from '../runtime/readable';\nimport { getRenderContext } from '../ssr/context';\nimport {\n requireAuth,\n requireGuest,\n requirePermission,\n requireRole,\n} from './policy';\n\nexport type {\n AccessDecision,\n AccessDenyDecision,\n AccessRedirectDecision,\n GroupHelperOptions,\n PageHelperOptions,\n RegisterRoutesOptions,\n RouteDefinition,\n RouteAuthOptions,\n RouteHandler,\n Route,\n RouteContext,\n RoutePolicy,\n RouteRenderResult,\n RouteRequestOptions,\n RouteRequestResult,\n ResolvedRoute,\n RouteMatch,\n RouteQuery,\n RouteSnapshot,\n RouteComponent,\n RouteOptions,\n ParsedSegment,\n LayoutScopeRecord,\n PageScopeRecord,\n RouteRecord,\n RouteManifest,\n} from '../common/router';\n\nimport type {\n AccessDecision,\n AccessDenyDecision,\n AccessRedirectDecision,\n GroupHelperOptions,\n PageHelperOptions,\n RegisterRoutesOptions,\n RouteDefinition,\n RouteAuthOptions,\n RouteHandler,\n Route,\n RouteContext,\n RoutePolicy,\n RouteRenderResult,\n RouteRequestOptions,\n RouteRequestResult,\n ResolvedRoute,\n RouteMatch,\n RouteQuery,\n RouteSnapshot,\n RouteComponent,\n RouteOptions,\n LayoutScopeRecord,\n PageScopeRecord,\n RouteRecord,\n RouteManifest,\n} from '../common/router';\n\n// ---------------------------------------------------------------------------\n// Module-level stores\n// ---------------------------------------------------------------------------\n\n/** Legacy flat route array — kept for resolver and route() accessor backward compat. */\ntype InternalRoute = Route & {\n fallbackPrefix?: string;\n};\n\ntype InternalRouteRecord = RouteRecord & {\n fallbackPrefix?: string;\n};\n\nconst routes: InternalRoute[] = [];\n\n/** Normalized route records built by the declarative registration API. */\nconst records: InternalRouteRecord[] = [];\n\ntype RegistrationScope = {\n kind: 'group' | 'page';\n pathPrefix: string;\n layout?: LayoutScopeRecord['component'];\n page?: PageScopeRecord['component'];\n policies: readonly RoutePolicy[];\n state: AccessScopeState;\n};\n\ntype RegistrationSession = {\n authConfigured: boolean;\n};\n\n/** Active registration scope stack during module-load-time registration. */\nconst registrationScopeStack: RegistrationScope[] = [];\nconst registrationSessionStack: RegistrationSession[] = [];\n\nconst namespaces = new Set<string>();\nlet registrationLocked = false;\n\ntype AccessScopeState = {\n guestOnly: boolean;\n authenticated: boolean;\n};\n\nlet defaultRouteAuthOptions: RouteAuthOptions | undefined;\nlet activeClientRouteAuthOptions: RouteAuthOptions | undefined;\n\nconst HAS_ROUTES_KEY = Symbol.for('__ASKR_HAS_ROUTES__');\n\nfunction setHasRoutes(value: boolean): void {\n try {\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n g[HAS_ROUTES_KEY] = value;\n } catch {\n // ignore\n }\n}\n\n// Initialize to false at module load.\nsetHasRoutes(false);\n\n// Route index by depth - maintains insertion order\nconst routesByDepth = new Map<number, Route[]>();\n\n/**\n * Parse route path depth\n */\nfunction getDepth(path: string): number {\n const normalized =\n path.endsWith('/') && path !== '/' ? path.slice(0, -1) : path;\n return normalized === '/' ? 0 : normalized.split('/').filter(Boolean).length;\n}\n\n// ---------------------------------------------------------------------------\n// WeakMap caches for external Route[] objects (e.g. SSR per-request tables)\n// Amortises parseSegments / computeRank across repeated resolveRouteFromRoutes\n// calls on the same route list (same object reference).\n// ---------------------------------------------------------------------------\n\n/** Pre-parsed segments for an externally supplied Route object. */\nconst routeSegsCache = new WeakMap<Route, ReturnType<typeof parseSegments>>();\n/** Pre-computed rank for an externally supplied Route object. */\nconst routeRankCache = new WeakMap<Route, number>();\n/** A rank-descending sorted copy of an external readonly Route array. */\nconst sortedListCache = new WeakMap<\n ReadonlyArray<Route>,\n ReadonlyArray<Route>\n>();\n\nfunction cachedSegs(r: Route): ReturnType<typeof parseSegments> {\n let s = routeSegsCache.get(r);\n if (!s) {\n s = parseSegments(r.path);\n routeSegsCache.set(r, s);\n }\n return s;\n}\n\nfunction cachedRank(r: Route): number {\n let n = routeRankCache.get(r);\n if (n === undefined) {\n n = computeRank(cachedSegs(r));\n routeRankCache.set(r, n);\n }\n return n;\n}\n\nfunction cachedSortedList(\n routeList: ReadonlyArray<Route>\n): ReadonlyArray<Route> {\n let sorted = sortedListCache.get(routeList);\n if (!sorted) {\n sorted = [...routeList].sort((a, b) => cachedRank(b) - cachedRank(a));\n sortedListCache.set(routeList, sorted);\n }\n return sorted;\n}\n\nlet currentRouteSnapshot = buildRouteSnapshot('/', '', '');\n\nconst currentRouteSource = (() =>\n currentRouteSnapshot) as ReadableSource<RouteSnapshot> &\n (() => RouteSnapshot);\n\ncurrentRouteSource._readers = new Map();\n\n// SSR helper: when rendering on the server, callers may set a location so that\n// render-time route() returns deterministic server values that match client\n// hydration. This is deliberately an opt-in escape for SSR and tests.\nlet serverLocation: string | null = null;\n\nexport function setServerLocation(url: string | null): void {\n serverLocation = url;\n}\n\nfunction isPromise<T>(value: T | Promise<T>): value is Promise<T> {\n return value instanceof Promise;\n}\n\nfunction buildRouteSnapshot(\n pathname: string,\n search: string,\n hash: string\n): RouteSnapshot {\n const query = makeQuery(search);\n const matches = computeMatchesFromRoutes(pathname, getActiveRoutes());\n\n return Object.freeze({\n path: pathname,\n params: deepFreeze({ ...matches[0]?.params }),\n query,\n hash: hash || null,\n matches: Object.freeze(matches),\n });\n}\n\nfunction setCurrentRouteSnapshot(\n pathname: string,\n search: string,\n hash: string\n): void {\n currentRouteSnapshot = buildRouteSnapshot(pathname, search, hash);\n\n const instance = getCurrentComponentInstance();\n markReadableDerivedSubscribersDirty(currentRouteSource);\n markReactivePropsDirtySource(currentRouteSource);\n notifyReadableReaders(currentRouteSource, instance);\n}\n\n// Compute matches for a specific route list.\nfunction matchFallbackPrefix(\n pathname: string,\n fallbackPrefix: string\n): Record<string, string> | null {\n const normalizedPath =\n pathname.endsWith('/') && pathname !== '/'\n ? pathname.slice(0, -1)\n : pathname;\n const normalizedPrefix =\n fallbackPrefix.endsWith('/') && fallbackPrefix !== '/'\n ? fallbackPrefix.slice(0, -1)\n : fallbackPrefix;\n\n if (normalizedPrefix === '/') {\n const urlParts =\n normalizedPath === '/' ? [] : normalizedPath.split('/').filter(Boolean);\n return {\n '*':\n urlParts.length === 0\n ? '/'\n : urlParts.length === 1\n ? urlParts[0]\n : '/' + urlParts.join('/'),\n };\n }\n\n if (\n normalizedPath !== normalizedPrefix &&\n !normalizedPath.startsWith(`${normalizedPrefix}/`)\n ) {\n return null;\n }\n\n const remainder =\n normalizedPath === normalizedPrefix\n ? '/'\n : normalizedPath.slice(normalizedPrefix.length + 1);\n const remainderParts =\n remainder === '/' ? [] : remainder.split('/').filter(Boolean);\n\n return {\n '*':\n remainderParts.length === 0\n ? '/'\n : remainderParts.length === 1\n ? remainderParts[0]\n : '/' + remainderParts.join('/'),\n };\n}\n\nfunction computeMatchesFromRoutes(\n pathname: string,\n routesList: readonly Route[]\n): RouteMatch[] {\n const bestMatch =\n routesList === routes\n ? getMatchingRecord(pathname, records)\n : findBestResolvedRouteFromRoutes(pathname, routesList);\n\n if (!bestMatch) {\n return [];\n }\n\n return [\n {\n path: 'route' in bestMatch ? bestMatch.route.path : bestMatch.record.path,\n params: deepFreeze({ ...bestMatch.params }),\n name:\n 'route' in bestMatch\n ? (bestMatch.route as { name?: string }).name\n : undefined,\n namespace:\n 'route' in bestMatch\n ? bestMatch.route.namespace\n : bestMatch.record.options.namespace,\n },\n ];\n}\n\nfunction findBestResolvedRouteFromRoutes(\n pathname: string,\n routeList: readonly Route[]\n): { route: Route; params: Record<string, string> } | null {\n const normalized =\n pathname.endsWith('/') && pathname !== '/'\n ? pathname.slice(0, -1)\n : pathname;\n const urlParts =\n normalized === '/' ? [] : normalized.split('/').filter(Boolean);\n\n const sorted = cachedSortedList(routeList);\n let bestRoute: Route | null = null;\n let bestParams: Record<string, string> = {};\n let bestRank = -Infinity;\n\n for (const route of sorted) {\n const internalRoute = route as InternalRoute;\n if (internalRoute.fallbackPrefix) {\n continue;\n }\n\n const rank = cachedRank(route);\n if (rank < bestRank) break;\n if (bestRoute !== null && rank === bestRank) continue;\n\n const params = matchSegments(urlParts, cachedSegs(route));\n if (params !== null) {\n bestRoute = route;\n bestParams = params;\n bestRank = rank;\n }\n }\n\n if (bestRoute !== null) {\n return { route: bestRoute, params: bestParams };\n }\n\n let bestFallback: InternalRoute | null = null;\n let bestFallbackParams: Record<string, string> | null = null;\n let bestPrefixLength = -1;\n\n for (const route of routeList) {\n const internalRoute = route as InternalRoute;\n if (!internalRoute.fallbackPrefix) {\n continue;\n }\n\n const params = matchFallbackPrefix(\n normalized,\n internalRoute.fallbackPrefix\n );\n if (params === null) {\n continue;\n }\n\n if (internalRoute.fallbackPrefix.length > bestPrefixLength) {\n bestFallback = internalRoute;\n bestFallbackParams = params;\n bestPrefixLength = internalRoute.fallbackPrefix.length;\n }\n }\n\n return bestFallback && bestFallbackParams\n ? { route: bestFallback, params: bestFallbackParams }\n : null;\n}\n\nfunction getActiveRoutes(): readonly Route[] {\n const renderContext = getRenderContext();\n return renderContext?.routes ?? routes;\n}\n\nfunction getActiveRouteAuthOptions(\n override?: RouteAuthOptions\n): RouteAuthOptions | undefined {\n if (override) {\n return override;\n }\n\n const renderContext = getRenderContext();\n return (\n renderContext?.routeAuth ??\n activeClientRouteAuthOptions ??\n defaultRouteAuthOptions\n );\n}\n\nexport function _setActiveRouteAuthOptions(\n auth: RouteAuthOptions | undefined\n): void {\n activeClientRouteAuthOptions = auth;\n}\n\nfunction getCurrentRegistrationSession(): RegistrationSession {\n return (\n registrationSessionStack[registrationSessionStack.length - 1] ?? {\n authConfigured: !!defaultRouteAuthOptions?.resolve,\n }\n );\n}\n\nfunction getCurrentAccessScopeState(): AccessScopeState {\n return (\n registrationScopeStack[registrationScopeStack.length - 1]?.state ?? {\n guestOnly: false,\n authenticated: false,\n }\n );\n}\n\nfunction getCurrentLayoutChain(): LayoutScopeRecord[] {\n const layoutChain: LayoutScopeRecord[] = [];\n\n for (const scope of registrationScopeStack) {\n if (scope.layout) {\n layoutChain.push({ component: scope.layout });\n }\n }\n\n return layoutChain;\n}\n\nfunction getCurrentPageChain(): PageScopeRecord[] {\n const pageChain: PageScopeRecord[] = [];\n\n for (const scope of registrationScopeStack) {\n if (scope.page) {\n pageChain.push({ component: scope.page });\n }\n }\n\n return pageChain;\n}\n\nfunction hasActivePageScope(): boolean {\n return registrationScopeStack.some((scope) => !!scope.page);\n}\n\nfunction getCurrentScopeKind(): RegistrationScope['kind'] | null {\n return (\n registrationScopeStack[registrationScopeStack.length - 1]?.kind ?? null\n );\n}\n\nfunction getCurrentPathPrefix(): string {\n return (\n registrationScopeStack[registrationScopeStack.length - 1]?.pathPrefix ?? ''\n );\n}\n\nfunction getCurrentInheritedPolicies(): RoutePolicy[] {\n const policies: RoutePolicy[] = [];\n\n for (const scope of registrationScopeStack) {\n if (scope.policies.length > 0) {\n policies.push(...scope.policies);\n }\n }\n\n return policies;\n}\n\n// ---------------------------------------------------------------------------\n// Registration lock\n// ---------------------------------------------------------------------------\n\n/**\n * Prevent route registrations after the app has started.\n * Enforced in production; tests may unlock explicitly.\n */\n\nexport function lockRouteRegistration(): void {\n registrationLocked = true;\n}\n\nexport function _lockRouteRegistrationForTests(): void {\n registrationLocked = true;\n}\n\nexport function _unlockRouteRegistrationForTests(): void {\n registrationLocked = false;\n}\n\n// ---------------------------------------------------------------------------\n// Path validation\n// ---------------------------------------------------------------------------\n\nfunction validateRoutePath(path: string): void {\n if (!path.startsWith('/')) {\n throw new Error(`Route path must begin with \"/\". Got: \"${path}\"`);\n }\n // Reject Express-style :param syntax — Askr uses {param} interpolation\n if (/:([^/{}]+)/.test(path)) {\n const suggested = path.replace(/:([^/{}]+)/g, '{$1}');\n throw new Error(\n `Route parameter syntax uses {name} interpolation, not :name. ` +\n `Use \"${suggested}\" instead of \"${path}\".`\n );\n }\n}\n\nfunction normalizeAbsoluteRoutePath(path: string): string {\n if (!path || path === '/') {\n return '/';\n }\n\n const normalized = path.endsWith('/') ? path.slice(0, -1) : path;\n return normalized || '/';\n}\n\nfunction joinRoutePaths(prefix: string, path: string): string {\n const normalizedPrefix = normalizeAbsoluteRoutePath(prefix || '/');\n const normalizedPath = path.replace(/^\\/+|\\/+$/g, '');\n\n if (!normalizedPath) {\n return normalizedPrefix;\n }\n\n return normalizedPrefix === '/'\n ? `/${normalizedPath}`\n : `${normalizedPrefix}/${normalizedPath}`;\n}\n\nfunction resolvePageScopePath(path: string): string {\n if (!path) {\n throw new Error('page(path, Component, fn) requires a non-empty path.');\n }\n\n if (path.startsWith('/')) {\n validateRoutePath(path);\n return normalizeAbsoluteRoutePath(path);\n }\n\n return joinRoutePaths(getCurrentPathPrefix(), path);\n}\n\nfunction resolveIndexPath(): string {\n return normalizeAbsoluteRoutePath(getCurrentPathPrefix() || '/');\n}\n\nfunction resolveRouteRegistrationPath(path: string): string {\n if (path.startsWith('/')) {\n if (hasActivePageScope()) {\n throw new Error(\n 'Child route paths inside page() must be relative. ' +\n `Use \"${path.slice(1)}\" instead of \"${path}\".`\n );\n }\n\n validateRoutePath(path);\n return normalizeAbsoluteRoutePath(path);\n }\n\n const prefix = getCurrentPathPrefix();\n\n if (!prefix) {\n throw new Error(`Route path must begin with \"/\". Got: \"${path}\"`);\n }\n\n return joinRoutePaths(prefix, path);\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: insert a RouteRecord in rank-descending order\n// so that resolveRoute can use first-match-wins without sorting.\n// Ties preserve declaration order (stable binary-search insertion).\n// ---------------------------------------------------------------------------\n\nfunction insertRecordSorted(record: RouteRecord): void {\n let lo = 0;\n let hi = records.length;\n // Find the insertion point: after all existing records with rank >= this one\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (records[mid].rank >= record.rank) lo = mid + 1;\n else hi = mid;\n }\n records.splice(lo, 0, record);\n}\n\n// ---------------------------------------------------------------------------\n// Internal helper: add a single pre-built Route object to the runtime stores\n// ---------------------------------------------------------------------------\n\nfunction addRouteToStores(routeObj: Route): void {\n routes.push(routeObj);\n setHasRoutes(true);\n\n const depth = getDepth(routeObj.path);\n let depthRoutes = routesByDepth.get(depth);\n if (!depthRoutes) {\n depthRoutes = [];\n routesByDepth.set(depth, depthRoutes);\n }\n depthRoutes.push(routeObj);\n\n if (routeObj.namespace) {\n namespaces.add(routeObj.namespace);\n }\n}\n\n// ---------------------------------------------------------------------------\n// lazy() — eager-prefetch code-split component wrapper\n// ---------------------------------------------------------------------------\n\n/** Promises from in-flight lazy() imports, drained by createSPA / hydrateSPA. */\nconst pendingLazy = new Set<Promise<unknown>>();\n\nconst outletContext = defineContext<unknown>(null);\n\nexport function Outlet(): unknown {\n return readContext(outletContext);\n}\n\n/**\n * Snapshot the current in-flight lazy() imports.\n * Boot uses this before clearing route state so manifest-based startup can\n * still await chunks that were kicked off during route module evaluation.\n */\nexport function _snapshotLazy(): Promise<unknown>[] {\n return [...pendingLazy];\n}\n\n/**\n * Declare a code-split route component. The `import()` fires immediately at\n * module evaluation time (creating a bundler split point), and the resolved\n * chunk is guaranteed to be available before the app mounts — so the renderer\n * always receives a plain synchronous function.\n *\n * ```ts\n * registerRoutes(() => {\n * group({ layout: AppLayout }, () => {\n * route('/', lazy(() => import('./pages/landing')));\n * route('/dashboard', lazy(() => import('./pages/dashboard')));\n * });\n * });\n * ```\n *\n * The module must export the component as its **default** export:\n * ```ts\n * // pages/dashboard.tsx\n * export default function DashboardPage() { … }\n * ```\n */\nexport function lazy(\n factory: () => Promise<{ default: RouteComponent } | RouteComponent>\n): RouteComponent {\n let resolved: RouteComponent | null = null;\n let loadError: unknown = null;\n\n const promise = factory().then(\n (mod) => {\n resolved =\n typeof mod === 'function'\n ? mod\n : (mod as { default: RouteComponent }).default;\n pendingLazy.delete(promise);\n },\n (err: unknown) => {\n loadError = err;\n pendingLazy.delete(promise);\n }\n );\n pendingLazy.add(promise);\n\n return (params) => {\n if (loadError) throw loadError as Error;\n if (!resolved) {\n throw new Error(\n 'lazy() component used before it was resolved. ' +\n 'Await createSPA() / hydrateSPA() to ensure all chunks load first.'\n );\n }\n return resolved(params);\n };\n}\n\n/**\n * Wait for all pending `lazy()` imports to settle.\n * Called automatically by `createSPA` / `hydrateSPA` before mounting.\n */\nexport function _drainLazy(\n additionalPending: Iterable<Promise<unknown>> = []\n): Promise<void> {\n const combined = new Set<Promise<unknown>>([\n ...additionalPending,\n ...pendingLazy,\n ]);\n if (combined.size === 0) return Promise.resolve();\n return Promise.allSettled(combined).then(() => undefined);\n}\n\nexport function group(options: GroupHelperOptions, fn: RouteDefinition): void;\nexport function group(options: GroupHelperOptions, fn: RouteDefinition): void {\n pushGroupScope(options, fn);\n}\n\nexport function page(\n path: string,\n Component: RouteComponent,\n fn: RouteDefinition\n): void;\nexport function page(\n path: string,\n Component: RouteComponent,\n options: PageHelperOptions,\n fn: RouteDefinition\n): void;\nexport function page(\n path: string,\n Component: RouteComponent,\n optionsOrFn: PageHelperOptions | RouteDefinition,\n maybeFn?: RouteDefinition\n): void {\n const options =\n typeof optionsOrFn === 'function' ? ({} as PageHelperOptions) : optionsOrFn;\n const fn = typeof optionsOrFn === 'function' ? optionsOrFn : maybeFn;\n\n if (typeof Component !== 'function') {\n throw new Error(\n 'page(path, Component, fn) requires a component function as the second argument.'\n );\n }\n\n if (typeof fn !== 'function') {\n throw new Error(\n 'page(path, Component, fn) requires a route definition callback as the final argument.'\n );\n }\n\n pushPageScope(path, Component, options, fn);\n}\n\nexport function index(Component: RouteComponent, options?: RouteOptions): void {\n registerRouteAtResolvedPath(resolveIndexPath(), Component, options);\n}\n\nexport function fallback(Component: RouteComponent): void {\n if (hasActivePageScope()) {\n if (getCurrentScopeKind() !== 'page') {\n throw new Error(\n 'fallback() inside page() must be declared directly in the page scope, not inside nested group().'\n );\n }\n\n registerRouteAtResolvedPath(\n `${getCurrentPathPrefix()}/*`,\n Component,\n undefined,\n { isFallback: true, fallbackPrefix: getCurrentPathPrefix() }\n );\n return;\n }\n\n const allowsRootFallback = registrationScopeStack.every(\n (scope) =>\n scope.policies.length === 0 &&\n !scope.state.guestOnly &&\n !scope.state.authenticated\n );\n\n if (!allowsRootFallback) {\n throw new Error(\n 'fallback() can only be registered at the root scope. ' +\n 'Use route(\"/*\", Component) if you need compatibility behavior.'\n );\n }\n\n registerRouteAtResolvedPath('/*', Component, undefined, {\n isFallback: true,\n fallbackPrefix: '/',\n });\n}\n\nfunction pushRegistrationScope(\n scope: RegistrationScope,\n fn: RouteDefinition\n): void {\n registrationScopeStack.push(scope);\n try {\n fn();\n } finally {\n registrationScopeStack.pop();\n }\n}\n\nfunction pushGroupScope(\n options: GroupHelperOptions,\n fn: RouteDefinition\n): void {\n const session = getCurrentRegistrationSession();\n validateAccessMetadata(options, {\n authConfigured: session.authConfigured,\n state: getCurrentAccessScopeState(),\n });\n const policies = compileNodePolicies(options);\n\n pushRegistrationScope(\n {\n kind: 'group',\n pathPrefix: getCurrentPathPrefix(),\n layout: options.layout,\n policies,\n state: nextAccessScopeState(options, getCurrentAccessScopeState()),\n },\n fn\n );\n}\n\nfunction pushPageScope(\n path: string,\n Component: RouteComponent,\n options: PageHelperOptions,\n fn: RouteDefinition\n): void {\n if (hasActivePageScope()) {\n throw new Error(\n 'page() cannot be nested inside another page(). ' +\n 'Use route() for child leaves or group() for inherited behavior inside the existing page scope.'\n );\n }\n\n const session = getCurrentRegistrationSession();\n validateAccessMetadata(options, {\n authConfigured: session.authConfigured,\n state: getCurrentAccessScopeState(),\n });\n\n const policies = compileNodePolicies(options);\n\n pushRegistrationScope(\n {\n kind: 'page',\n pathPrefix: resolvePageScopePath(path),\n page: Component,\n policies,\n state: nextAccessScopeState(options, getCurrentAccessScopeState()),\n },\n fn\n );\n}\n\nfunction hasBuiltInAuthMetadata(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>\n): boolean {\n return node.auth !== undefined || !!node.role || !!node.permission;\n}\n\nfunction validateSameNodeAccessMetadata(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>\n): void {\n if (node.auth === 'guest' && (!!node.role || !!node.permission)) {\n throw new Error(\n 'Guest-only routes cannot be combined with role or permission requirements.'\n );\n }\n}\n\nfunction validateAccessMetadata(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>,\n context: {\n authConfigured: boolean;\n state: AccessScopeState;\n }\n): void {\n validateSameNodeAccessMetadata(node);\n\n const requiresAuthenticated =\n node.auth === true || !!node.role || !!node.permission;\n\n if (\n node.auth === 'guest' &&\n (context.state.authenticated || !!node.role || !!node.permission)\n ) {\n throw new Error(\n 'Guest-only routes cannot be combined with authenticated access requirements.'\n );\n }\n\n if (context.state.guestOnly && requiresAuthenticated) {\n throw new Error(\n 'Child routes cannot weaken a guest-only access scope with authenticated requirements.'\n );\n }\n\n if (hasBuiltInAuthMetadata(node) && !context.authConfigured) {\n throw new Error(\n 'Routes using `auth`, `role`, or `permission` require `auth.resolve` in registerRoutes(...).'\n );\n }\n}\n\nfunction nextAccessScopeState(\n node: Pick<GroupHelperOptions | RouteOptions, 'auth' | 'role' | 'permission'>,\n state: AccessScopeState\n): AccessScopeState {\n const requiresAuthenticated =\n node.auth === true || !!node.role || !!node.permission;\n\n return {\n guestOnly: state.guestOnly || node.auth === 'guest',\n authenticated: state.authenticated || requiresAuthenticated,\n };\n}\n\nfunction compileNodePolicies(\n node: Pick<\n RouteOptions | GroupHelperOptions,\n 'auth' | 'role' | 'permission' | 'policies'\n >\n): RoutePolicy[] {\n validateSameNodeAccessMetadata(node);\n\n const compiled: RoutePolicy[] = [];\n\n if (node.auth === true) {\n compiled.push(requireAuth());\n } else if (node.auth === 'guest') {\n compiled.push(requireGuest());\n }\n\n if (node.role) {\n compiled.push(requireRole(node.role));\n }\n\n if (node.permission) {\n compiled.push(requirePermission(node.permission));\n }\n\n if (node.policies?.length) {\n compiled.push(...node.policies);\n }\n\n return compiled;\n}\n\nfunction normalizeRouteOptions(\n options: RouteOptions | undefined\n): RouteOptions | undefined {\n if (!options) {\n return undefined;\n }\n\n const loader = options.loader;\n const policies = compileNodePolicies(options);\n\n if (\n !loader &&\n !options.entries &&\n policies.length === 0 &&\n !options.title &&\n !options.namespace &&\n options.auth === undefined &&\n !options.role &&\n !options.permission\n ) {\n return undefined;\n }\n\n return {\n ...(loader ? { loader } : {}),\n ...(options.entries ? { entries: options.entries } : {}),\n ...(options.auth !== undefined ? { auth: options.auth } : {}),\n ...(options.role ? { role: options.role } : {}),\n ...(options.permission ? { permission: options.permission } : {}),\n ...(policies.length > 0 ? { policies } : {}),\n ...(options.title ? { title: options.title } : {}),\n ...(options.namespace ? { namespace: options.namespace } : {}),\n };\n}\n\nfunction applyPageChain(\n pageChain: readonly PageScopeRecord[],\n params: Record<string, string>,\n content: unknown\n): unknown {\n let nextContent = content;\n\n for (let i = pageChain.length - 1; i >= 0; i--) {\n nextContent = outletContext.Scope({\n value: nextContent,\n children: pageChain[i].component(params),\n });\n }\n\n return nextContent;\n}\n\nfunction registerRouteAtResolvedPath(\n path: string,\n Component: RouteComponent,\n options?: RouteOptions,\n metadata?: {\n isFallback?: boolean;\n fallbackPrefix?: string;\n }\n): void {\n validateAccessMetadata(options ?? {}, {\n authConfigured: getCurrentRegistrationSession().authConfigured,\n state: getCurrentAccessScopeState(),\n });\n\n const chain = getCurrentLayoutChain();\n const pageChain = getCurrentPageChain();\n const segments = parseSegments(path);\n const rank = computeRank(segments);\n const isFallback = metadata?.isFallback ?? path === '/*';\n const comp = Component;\n const normalizedOptions = normalizeRouteOptions(options);\n const policies = [\n ...getCurrentInheritedPolicies(),\n ...(normalizedOptions?.policies ?? []),\n ];\n\n const handler: RouteHandler = (params) => {\n let content = comp(params);\n\n content = applyPageChain(pageChain, params, content);\n\n for (let i = chain.length - 1; i >= 0; i--) {\n content = chain[i].component({ children: content });\n }\n\n return content;\n };\n\n const record: InternalRouteRecord = {\n path,\n component: comp,\n segments,\n rank,\n layoutChain: chain,\n pageChain,\n options: normalizedOptions\n ? {\n ...normalizedOptions,\n ...(policies.length > 0 ? { policies } : {}),\n }\n : policies.length > 0\n ? { policies }\n : {},\n isFallback,\n handler,\n ...(metadata?.fallbackPrefix\n ? { fallbackPrefix: metadata.fallbackPrefix }\n : {}),\n };\n\n insertRecordSorted(record);\n addRouteToStores({\n path,\n handler,\n namespace: normalizedOptions?.namespace ?? options?.namespace,\n ...(metadata?.fallbackPrefix\n ? { fallbackPrefix: metadata.fallbackPrefix }\n : {}),\n });\n}\n\nexport function registerRoutes(\n definition: RouteDefinition,\n options: RegisterRoutesOptions = {}\n): void {\n defaultRouteAuthOptions = options.auth;\n\n registrationSessionStack.push({\n authConfigured: !!options.auth?.resolve,\n });\n try {\n definition();\n } finally {\n registrationSessionStack.pop();\n }\n}\n\n// ---------------------------------------------------------------------------\n// route() — dual-purpose: registration (module load) + accessor (render time)\n// ---------------------------------------------------------------------------\n\nfunction readCurrentRouteSnapshot(): RouteSnapshot {\n const instance = getCurrentComponentInstance();\n if (!instance) {\n throw new Error(\n 'currentRoute() can only be called during component render execution. ' +\n 'Call currentRoute() from inside your component function.'\n );\n }\n\n let pathname = '/';\n let search = '';\n let hash = '';\n const renderContext = getRenderContext();\n\n if (instance.ssr && renderContext?.url) {\n const parsed = parseLocation(renderContext.url);\n pathname = parsed.pathname;\n search = parsed.search;\n hash = parsed.hash;\n } else if (typeof window !== 'undefined' && window.location) {\n pathname = window.location.pathname || '/';\n search = window.location.search || '';\n hash = window.location.hash || '';\n } else if (serverLocation) {\n const parsed = parseLocation(serverLocation);\n pathname = parsed.pathname;\n search = parsed.search;\n hash = parsed.hash;\n }\n\n const query = makeQuery(search);\n const matches = computeMatchesFromRoutes(pathname, getActiveRoutes());\n const instanceParams = instance.props as Record<string, string>;\n const routeParams =\n Object.keys(instanceParams).length > 0\n ? instanceParams\n : (matches[0]?.params ?? {});\n const params = deepFreeze({\n ...routeParams,\n });\n\n return Object.freeze({\n path: pathname,\n params,\n query,\n hash: hash || null,\n matches: Object.freeze(matches),\n });\n}\n\nexport function currentRoute(): RouteSnapshot {\n const instance = getCurrentComponentInstance();\n if (!instance) {\n throw new Error(\n 'currentRoute() can only be called during component render execution. ' +\n 'Call currentRoute() from inside your component function.'\n );\n }\n\n if (typeof window === 'undefined' || instance.ssr) {\n return readCurrentRouteSnapshot();\n }\n\n if (currentRouteSnapshot.path !== (window.location.pathname || '/')) {\n recordReadableRead(currentRouteSource);\n return readCurrentRouteSnapshot();\n }\n\n recordReadableRead(currentRouteSource);\n return readCurrentRouteSnapshot();\n}\n\nexport function syncCurrentRouteSnapshot(\n pathname: string,\n search: string,\n hash: string\n): void {\n setCurrentRouteSnapshot(pathname, search, hash);\n}\n\n/**\n * Register a route.\n *\n * ```ts\n * route('/posts/{slug}', PostPage, {\n * loader: ({ params }) => getPost(params.slug),\n * entries: async () => getPosts().map(p => ({ slug: p.slug })),\n * title: 'Post',\n * policies:[requireAuth()],\n * });\n * ```\n */\nexport function route(\n path: string,\n Component: RouteComponent,\n options?: RouteOptions\n): void;\nexport function route(\n path: string,\n Component: RouteComponent,\n options?: RouteOptions\n): void {\n if (getExecutionModel() === 'islands') {\n throw new Error(\n 'Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead.'\n );\n }\n\n // ── Render-time accessor (no arguments) ─────────────────────────────────\n if (typeof path === 'undefined') {\n throw new Error(\n 'route() is only for route registration. Use currentRoute() inside components.'\n );\n }\n\n // ── Registration mode ────────────────────────────────────────────────────\n\n // Disallow registration during SSR render\n const currentInst = getCurrentComponentInstance();\n if (currentInst && currentInst.ssr) {\n throw new Error(\n 'route() cannot be called during SSR rendering. Register routes at module load time instead.'\n );\n }\n\n if (registrationLocked) {\n throw new Error(\n 'Route registration is locked after app startup. ' +\n 'Register routes at module load time before calling createSPA or createSSR.'\n );\n }\n\n if (typeof Component !== 'function') {\n throw new Error(\n 'route(path, Component) requires a component function as the second argument. ' +\n 'Passing JSX elements or VNodes directly is not supported.'\n );\n }\n\n registerRouteAtResolvedPath(\n resolveRouteRegistrationPath(path),\n Component,\n options\n );\n}\n\n// ---------------------------------------------------------------------------\n// Manifest access\n// ---------------------------------------------------------------------------\n\n/**\n * Return the normalized route manifest built from registered route definitions.\n *\n * Pass this to `createSPA`, `hydrateSPA`, or `renderToString` as the\n * authoritative routing input:\n *\n * ```ts\n * import { getManifest } from '@askrjs/askr/router';\n * await createSPA({ root: '#app', manifest: getManifest() });\n * ```\n */\nexport function getManifest(): RouteManifest {\n return {\n records: [...records],\n ...(defaultRouteAuthOptions ? { auth: defaultRouteAuthOptions } : {}),\n };\n}\n\n/**\n * Internal: apply a pre-built manifest to the runtime stores without running\n * route() again. Called by createSPA / hydrateSPA when a manifest is passed.\n */\nexport function _applyManifest(manifest: RouteManifest): void {\n defaultRouteAuthOptions = manifest.auth;\n for (const record of manifest.records) {\n insertRecordSorted(record as InternalRouteRecord);\n addRouteToStores({\n path: record.path,\n handler: record.handler,\n namespace: record.options.namespace,\n ...('fallbackPrefix' in record &&\n typeof (record as InternalRouteRecord).fallbackPrefix === 'string'\n ? {\n fallbackPrefix: (record as InternalRouteRecord).fallbackPrefix,\n }\n : {}),\n });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Route collection helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Get all registered routes (flat list, insertion order).\n * Prefer `getManifest()` when metadata (loader, policies, entries) is needed.\n */\nexport function getRoutes(): Route[] {\n return [...routes];\n}\n\n/** Get routes for a specific namespace. */\nexport function getNamespaceRoutes(namespace: string): Route[] {\n return routes.filter((r) => r.namespace === namespace);\n}\n\n/** Unload all routes from a namespace (for MFE unmounting). */\nexport function unloadNamespace(namespace: string): number {\n const before = routes.length;\n\n for (let i = routes.length - 1; i >= 0; i--) {\n if (routes[i].namespace === namespace) {\n const removed = routes[i];\n routes.splice(i, 1);\n\n const depth = getDepth(removed.path);\n const depthRoutes = routesByDepth.get(depth);\n if (depthRoutes) {\n const idx = depthRoutes.indexOf(removed);\n if (idx >= 0) depthRoutes.splice(idx, 1);\n }\n }\n }\n\n // Remove matching records too\n for (let i = records.length - 1; i >= 0; i--) {\n if (records[i].options.namespace === namespace) {\n records.splice(i, 1);\n }\n }\n\n namespaces.delete(namespace);\n return before - routes.length;\n}\n\n/** Clear all registered routes and records (testing / boot reset). */\nexport function clearRoutes(): void {\n routes.length = 0;\n records.length = 0;\n namespaces.clear();\n routesByDepth.clear();\n registrationScopeStack.length = 0;\n registrationSessionStack.length = 0;\n registrationLocked = false;\n defaultRouteAuthOptions = undefined;\n activeClientRouteAuthOptions = undefined;\n setHasRoutes(false);\n pendingLazy.clear();\n}\n\n/**\n * Get all loaded namespaces (MFE identifiers)\n */\nexport function getLoadedNamespaces(): string[] {\n return Array.from(namespaces);\n}\n\nfunction findBestScopedFallbackRecord(\n pathname: string,\n routeRecords: readonly RouteRecord[]\n): { record: InternalRouteRecord; params: Record<string, string> } | null {\n let bestRecord: InternalRouteRecord | null = null;\n let bestParams: Record<string, string> | null = null;\n let bestPrefixLength = -1;\n\n for (const routeRecord of routeRecords) {\n const record = routeRecord as InternalRouteRecord;\n if (!record.fallbackPrefix) {\n continue;\n }\n\n const params = matchFallbackPrefix(pathname, record.fallbackPrefix);\n if (params === null) {\n continue;\n }\n\n if (record.fallbackPrefix.length > bestPrefixLength) {\n bestRecord = record;\n bestParams = params;\n bestPrefixLength = record.fallbackPrefix.length;\n }\n }\n\n return bestRecord && bestParams\n ? { record: bestRecord, params: bestParams }\n : null;\n}\n\n/**\n * Resolve a path to a route handler.\n *\n * Hot path: walks the module-level `records[]` array which is kept sorted by\n * rank descending at registration time — so the first `matchSegments` hit is\n * always the most specific match. No per-call allocations for the common\n * case of purely-static routes.\n */\nexport function resolveRoute(pathname: string): ResolvedRoute | null {\n const normalized =\n pathname.endsWith('/') && pathname !== '/'\n ? pathname.slice(0, -1)\n : pathname;\n const urlParts =\n normalized === '/' ? [] : normalized.split('/').filter(Boolean);\n\n for (const record of records) {\n if (record.fallbackPrefix) {\n continue;\n }\n\n const params = matchSegments(urlParts, record.segments);\n if (params !== null) {\n return { handler: record.handler, params };\n }\n }\n\n const fallbackMatch = findBestScopedFallbackRecord(normalized, records);\n return fallbackMatch\n ? { handler: fallbackMatch.record.handler, params: fallbackMatch.params }\n : null;\n}\n\nfunction getMatchingRecord(\n target: string,\n routeRecords: readonly RouteRecord[]\n): { record: RouteRecord; params: Record<string, string> } | null {\n const location = parseLocation(target);\n const normalized =\n location.pathname.endsWith('/') && location.pathname !== '/'\n ? location.pathname.slice(0, -1)\n : location.pathname;\n const urlParts =\n normalized === '/' ? [] : normalized.split('/').filter(Boolean);\n\n for (const record of routeRecords) {\n const internalRecord = record as InternalRouteRecord;\n if (internalRecord.fallbackPrefix) {\n continue;\n }\n\n const params = matchSegments(urlParts, record.segments);\n if (params !== null) {\n return { record, params };\n }\n }\n\n return findBestScopedFallbackRecord(normalized, routeRecords);\n}\n\nfunction getRoutePolicies(\n options: RouteOptions | undefined\n): readonly RoutePolicy[] {\n if (!options) {\n return [];\n }\n\n if (options.policies?.length) {\n return options.policies;\n }\n\n return compileNodePolicies(options);\n}\n\nfunction getDefaultRouteMode(): RouteContext['mode'] {\n if (typeof window !== 'undefined') {\n return 'spa';\n }\n\n return 'ssr';\n}\n\nfunction buildRenderResult(\n record: RouteRecord,\n params: Record<string, string>\n): RouteRenderResult {\n return {\n kind: 'render',\n handler: record.handler,\n params,\n };\n}\n\nfunction continueRoutePolicies(\n policies: readonly RoutePolicy[],\n context: RouteContext,\n record: RouteRecord,\n params: Record<string, string>,\n startIndex = 0\n): RouteRequestResult | Promise<RouteRequestResult> {\n for (let index = startIndex; index < policies.length; index += 1) {\n const policyResult = policies[index](context);\n\n if (isPromise(policyResult)) {\n return policyResult.then((next) => {\n if (next.kind !== 'allow') {\n return next;\n }\n\n return continueRoutePolicies(\n policies,\n context,\n record,\n params,\n index + 1\n );\n });\n }\n\n if (policyResult.kind !== 'allow') {\n return policyResult;\n }\n }\n\n return buildRenderResult(record, params);\n}\n\nexport function resolveRouteRequest(\n target: string,\n options: RouteRequestOptions = {}\n): RouteRequestResult | Promise<RouteRequestResult> {\n const routeRecords = options.manifest?.records ?? records;\n const match = getMatchingRecord(target, routeRecords);\n\n if (!match) {\n return null;\n }\n\n const { record, params } = match;\n const policies = getRoutePolicies(record.options);\n\n if (policies.length === 0) {\n return buildRenderResult(record, params);\n }\n\n const signal =\n options.signal ??\n getRenderContext()?.signal ??\n new AbortController().signal;\n const mode = options.mode ?? getDefaultRouteMode();\n const auth = getActiveRouteAuthOptions(\n options.auth ?? options.manifest?.auth\n );\n const baseContext = buildRouteContextBase(target, params, {\n mode,\n signal,\n });\n\n const finalize = (authState: { session: unknown; user: unknown }) =>\n continueRoutePolicies(\n policies,\n buildRouteContext(target, params, {\n mode,\n signal,\n auth,\n session: authState.session,\n user: authState.user,\n }),\n record,\n params\n );\n\n if (!auth?.resolve) {\n return finalize({ session: null, user: null });\n }\n\n const authState = auth.resolve(baseContext);\n if (isPromise(authState)) {\n return authState.then((next) => finalize(next));\n }\n\n return finalize(authState);\n}\n\n/**\n * Resolve a path against an explicit route list (e.g. an SSR per-render\n * context). When called with the global `routes` array this delegates to\n * the faster `resolveRoute` which uses pre-sorted `records[]`.\n *\n * For externally supplied lists the function:\n * 1. Builds a rank-sorted copy of the list on first call and caches it\n * in a WeakMap so subsequent resolutions against the same list pay\n * zero sort cost.\n * 2. Uses pre-parsed `ParsedSegment[]` from a WeakMap cache so no string\n * splitting or segment parsing occurs on the hot path.\n * 3. Uses a running-best with an early-exit once the sorted list reaches\n * a rank that cannot beat the current best match.\n */\nexport function resolveRouteFromRoutes(\n pathname: string,\n routeList: readonly Route[]\n): ResolvedRoute | null {\n if (routeList === routes) return resolveRoute(pathname);\n\n const match = findBestResolvedRouteFromRoutes(pathname, routeList);\n return match ? { handler: match.route.handler, params: match.params } : null;\n}\n"],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ declare function syncDerivedDependencySubscriptions(subscriber: DerivedSubscribe
|
|
|
21
21
|
declare function clearDerivedDependencySubscriptions(subscriber: DerivedSubscriber, sources: Set<ReadableSource<unknown>>): void;
|
|
22
22
|
declare function markReadableDerivedSubscribersDirty(source: ReadableSource<unknown>): void;
|
|
23
23
|
declare function markReactivePropsDirtySource(source: ReadableSource<unknown>): void;
|
|
24
|
-
declare function notifyReadableReaders(source: ReadableSource<unknown
|
|
24
|
+
declare function notifyReadableReaders(source: ReadableSource<unknown>, skipInstance?: ComponentInstance | null): boolean;
|
|
25
25
|
//#endregion
|
|
26
26
|
export { ReadableSource };
|
|
27
27
|
//# sourceMappingURL=readable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readable.d.ts","names":[],"sources":["../../src/runtime/readable.ts"],"mappings":";;;UAGiB,iBAAA;EACf,UAAA;EACA,yBAAA,GAA4B,GAAA,CAAI,cAAA;AAAA;AAAA,UAGjB,cAAA;EAAA,IACX,CAAA;EACJ,YAAA;EACA,QAAA,GAAW,GAAA,CAAI,iBAAA;EACf,mBAAA,GAAsB,GAAA,CAAI,iBAAA;AAAA;AAAA,iBAGZ,iBAAA,CAAkB,MAAA;AAAA,iBAkBlB,kBAAA,CAAmB,MAAA,EAAQ,cAAA;AAAA,iBA4B3B,2BAAA,GAAA,CACd,cAAA,EAAgB,GAAA,CAAI,cAAA,YACpB,EAAA,QAAU,CAAA,GACT,CAAA;AAAA,iBAWa,6BAAA,CACd,QAAA,EAAU,iBAAA;AAAA,iBAoCI,4BAAA,CACd,QAAA,EAAU,iBAAA;AAAA,iBAaI,uBAAA,GAAA,CACd,UAAA,EAAY,iBAAA,EACZ,EAAA,QAAU,CAAA,GACT,CAAA;AAAA,iBAaa,kCAAA,CACd,UAAA,EAAY,iBAAA,EACZ,WAAA,EAAa,GAAA,CAAI,cAAA,YACjB,WAAA,EAAa,GAAA,CAAI,cAAA;AAAA,iBAkBH,mCAAA,CACd,UAAA,EAAY,iBAAA,EACZ,OAAA,EAAS,GAAA,CAAI,cAAA;AAAA,iBAQC,mCAAA,CACd,MAAA,EAAQ,cAAA;AAAA,iBAYM,4BAAA,CACd,MAAA,EAAQ,cAAA;AAAA,iBAaM,qBAAA,CACd,MAAA,EAAQ,cAAA"}
|
|
1
|
+
{"version":3,"file":"readable.d.ts","names":[],"sources":["../../src/runtime/readable.ts"],"mappings":";;;UAGiB,iBAAA;EACf,UAAA;EACA,yBAAA,GAA4B,GAAA,CAAI,cAAA;AAAA;AAAA,UAGjB,cAAA;EAAA,IACX,CAAA;EACJ,YAAA;EACA,QAAA,GAAW,GAAA,CAAI,iBAAA;EACf,mBAAA,GAAsB,GAAA,CAAI,iBAAA;AAAA;AAAA,iBAGZ,iBAAA,CAAkB,MAAA;AAAA,iBAkBlB,kBAAA,CAAmB,MAAA,EAAQ,cAAA;AAAA,iBA4B3B,2BAAA,GAAA,CACd,cAAA,EAAgB,GAAA,CAAI,cAAA,YACpB,EAAA,QAAU,CAAA,GACT,CAAA;AAAA,iBAWa,6BAAA,CACd,QAAA,EAAU,iBAAA;AAAA,iBAoCI,4BAAA,CACd,QAAA,EAAU,iBAAA;AAAA,iBAaI,uBAAA,GAAA,CACd,UAAA,EAAY,iBAAA,EACZ,EAAA,QAAU,CAAA,GACT,CAAA;AAAA,iBAaa,kCAAA,CACd,UAAA,EAAY,iBAAA,EACZ,WAAA,EAAa,GAAA,CAAI,cAAA,YACjB,WAAA,EAAa,GAAA,CAAI,cAAA;AAAA,iBAkBH,mCAAA,CACd,UAAA,EAAY,iBAAA,EACZ,OAAA,EAAS,GAAA,CAAI,cAAA;AAAA,iBAQC,mCAAA,CACd,MAAA,EAAQ,cAAA;AAAA,iBAYM,4BAAA,CACd,MAAA,EAAQ,cAAA;AAAA,iBAaM,qBAAA,CACd,MAAA,EAAQ,cAAA,WACR,YAAA,GAAe,iBAAA"}
|
package/dist/runtime/readable.js
CHANGED
|
@@ -94,11 +94,12 @@ function markReactivePropsDirtySource(source) {
|
|
|
94
94
|
globalThis.__ASKR_RENDERER?.markReactivePropsDirtySource?.(source);
|
|
95
95
|
} catch {}
|
|
96
96
|
}
|
|
97
|
-
function notifyReadableReaders(source) {
|
|
97
|
+
function notifyReadableReaders(source, skipInstance) {
|
|
98
98
|
const readers = source._readers;
|
|
99
99
|
let didScheduleUpdate = false;
|
|
100
100
|
if (!readers || readers.size === 0) return false;
|
|
101
101
|
for (const [instance, token] of readers) {
|
|
102
|
+
if (skipInstance && instance === skipInstance) continue;
|
|
102
103
|
if (instance.lastRenderToken !== token) continue;
|
|
103
104
|
if (instance.hasPendingUpdate) continue;
|
|
104
105
|
instance.hasPendingUpdate = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readable.js","names":[],"sources":["../../src/runtime/readable.ts"],"sourcesContent":["import { globalScheduler } from './scheduler';\nimport { getCurrentInstance, type ComponentInstance } from './component';\n\nexport interface DerivedSubscriber {\n _markDirty(): void;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n}\n\nexport interface ReadableSource<T = unknown> {\n (): T;\n _hasBeenRead?: boolean;\n _readers?: Map<ComponentInstance, number>;\n _derivedSubscribers?: Set<DerivedSubscriber>;\n}\n\nexport function markReadableUsage(source: unknown): void {\n if (\n source &&\n typeof source === 'function' &&\n ('_hasBeenRead' in source || '_readers' in source)\n ) {\n (source as ReadableSource<unknown>)._hasBeenRead = true;\n }\n}\n\ntype RendererBridge = {\n markReactivePropsDirtySource?: (source: ReadableSource<unknown>) => void;\n};\n\nlet currentDerivedSubscriber: DerivedSubscriber | null = null;\nlet suppressComponentReadTrackingDepth = 0;\nlet currentFineGrainedReadSources: Set<ReadableSource<unknown>> | null = null;\n\nexport function recordReadableRead(source: ReadableSource<unknown>): void {\n if (currentFineGrainedReadSources) {\n currentFineGrainedReadSources.add(source);\n return;\n }\n\n if (currentDerivedSubscriber) {\n if (!currentDerivedSubscriber._pendingDependencySources) {\n currentDerivedSubscriber._pendingDependencySources = new Set();\n }\n currentDerivedSubscriber._pendingDependencySources.add(source);\n }\n\n if (suppressComponentReadTrackingDepth > 0) {\n return;\n }\n\n const inst = getCurrentInstance();\n if (!inst || inst._currentRenderToken === undefined) {\n return;\n }\n\n if (!inst._pendingReadSources) {\n inst._pendingReadSources = new Set();\n }\n inst._pendingReadSources.add(source);\n}\n\nexport function withFineGrainedReadTracking<T>(\n pendingSources: Set<ReadableSource<unknown>>,\n fn: () => T\n): T {\n const previousPendingSources = currentFineGrainedReadSources;\n currentFineGrainedReadSources = pendingSources;\n\n try {\n return fn();\n } finally {\n currentFineGrainedReadSources = previousPendingSources;\n }\n}\n\nexport function finalizeReadableSubscriptions(\n instance: ComponentInstance\n): void {\n const newSet = instance._pendingReadSources;\n const oldSet = instance._lastReadSources;\n const token = instance._currentRenderToken;\n\n if (token === undefined) {\n return;\n }\n\n if (oldSet) {\n for (const source of oldSet) {\n if (!newSet?.has(source)) {\n source._readers?.delete(instance);\n }\n }\n }\n\n instance.lastRenderToken = token;\n\n if (newSet) {\n for (const source of newSet) {\n let readers = source._readers;\n if (!readers) {\n readers = new Map();\n source._readers = readers;\n }\n readers.set(instance, instance.lastRenderToken ?? 0);\n }\n }\n\n instance._lastReadSources = newSet ?? new Set();\n instance._pendingReadSources = undefined;\n instance._currentRenderToken = undefined;\n}\n\nexport function cleanupReadableSubscriptions(\n instance: ComponentInstance\n): void {\n const sources = instance._lastReadSources;\n if (!sources || sources.size === 0) {\n return;\n }\n\n for (const source of sources) {\n source._readers?.delete(instance);\n }\n instance._lastReadSources = new Set();\n}\n\nexport function withDerivedReadTracking<T>(\n subscriber: DerivedSubscriber,\n fn: () => T\n): T {\n const prevDerivedSubscriber = currentDerivedSubscriber;\n currentDerivedSubscriber = subscriber;\n suppressComponentReadTrackingDepth += 1;\n\n try {\n return fn();\n } finally {\n suppressComponentReadTrackingDepth -= 1;\n currentDerivedSubscriber = prevDerivedSubscriber;\n }\n}\n\nexport function syncDerivedDependencySubscriptions(\n subscriber: DerivedSubscriber,\n prevSources: Set<ReadableSource<unknown>>,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n for (const source of prevSources) {\n if (!nextSources.has(source)) {\n source._derivedSubscribers?.delete(subscriber);\n }\n }\n\n for (const source of nextSources) {\n let subscribers = source._derivedSubscribers;\n if (!subscribers) {\n subscribers = new Set();\n source._derivedSubscribers = subscribers;\n }\n subscribers.add(subscriber);\n }\n}\n\nexport function clearDerivedDependencySubscriptions(\n subscriber: DerivedSubscriber,\n sources: Set<ReadableSource<unknown>>\n): void {\n for (const source of sources) {\n source._derivedSubscribers?.delete(subscriber);\n }\n sources.clear();\n}\n\nexport function markReadableDerivedSubscribersDirty(\n source: ReadableSource<unknown>\n): void {\n const subscribers = source._derivedSubscribers;\n if (!subscribers || subscribers.size === 0) {\n return;\n }\n\n for (const subscriber of subscribers) {\n subscriber._markDirty();\n }\n}\n\nexport function markReactivePropsDirtySource(\n source: ReadableSource<unknown>\n): void {\n try {\n (\n globalThis as {\n __ASKR_RENDERER?: RendererBridge;\n }\n ).__ASKR_RENDERER?.markReactivePropsDirtySource?.(source);\n } catch {\n // Keep readable notifications side-effect safe.\n }\n}\n\nexport function notifyReadableReaders(\n source: ReadableSource<unknown
|
|
1
|
+
{"version":3,"file":"readable.js","names":[],"sources":["../../src/runtime/readable.ts"],"sourcesContent":["import { globalScheduler } from './scheduler';\nimport { getCurrentInstance, type ComponentInstance } from './component';\n\nexport interface DerivedSubscriber {\n _markDirty(): void;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n}\n\nexport interface ReadableSource<T = unknown> {\n (): T;\n _hasBeenRead?: boolean;\n _readers?: Map<ComponentInstance, number>;\n _derivedSubscribers?: Set<DerivedSubscriber>;\n}\n\nexport function markReadableUsage(source: unknown): void {\n if (\n source &&\n typeof source === 'function' &&\n ('_hasBeenRead' in source || '_readers' in source)\n ) {\n (source as ReadableSource<unknown>)._hasBeenRead = true;\n }\n}\n\ntype RendererBridge = {\n markReactivePropsDirtySource?: (source: ReadableSource<unknown>) => void;\n};\n\nlet currentDerivedSubscriber: DerivedSubscriber | null = null;\nlet suppressComponentReadTrackingDepth = 0;\nlet currentFineGrainedReadSources: Set<ReadableSource<unknown>> | null = null;\n\nexport function recordReadableRead(source: ReadableSource<unknown>): void {\n if (currentFineGrainedReadSources) {\n currentFineGrainedReadSources.add(source);\n return;\n }\n\n if (currentDerivedSubscriber) {\n if (!currentDerivedSubscriber._pendingDependencySources) {\n currentDerivedSubscriber._pendingDependencySources = new Set();\n }\n currentDerivedSubscriber._pendingDependencySources.add(source);\n }\n\n if (suppressComponentReadTrackingDepth > 0) {\n return;\n }\n\n const inst = getCurrentInstance();\n if (!inst || inst._currentRenderToken === undefined) {\n return;\n }\n\n if (!inst._pendingReadSources) {\n inst._pendingReadSources = new Set();\n }\n inst._pendingReadSources.add(source);\n}\n\nexport function withFineGrainedReadTracking<T>(\n pendingSources: Set<ReadableSource<unknown>>,\n fn: () => T\n): T {\n const previousPendingSources = currentFineGrainedReadSources;\n currentFineGrainedReadSources = pendingSources;\n\n try {\n return fn();\n } finally {\n currentFineGrainedReadSources = previousPendingSources;\n }\n}\n\nexport function finalizeReadableSubscriptions(\n instance: ComponentInstance\n): void {\n const newSet = instance._pendingReadSources;\n const oldSet = instance._lastReadSources;\n const token = instance._currentRenderToken;\n\n if (token === undefined) {\n return;\n }\n\n if (oldSet) {\n for (const source of oldSet) {\n if (!newSet?.has(source)) {\n source._readers?.delete(instance);\n }\n }\n }\n\n instance.lastRenderToken = token;\n\n if (newSet) {\n for (const source of newSet) {\n let readers = source._readers;\n if (!readers) {\n readers = new Map();\n source._readers = readers;\n }\n readers.set(instance, instance.lastRenderToken ?? 0);\n }\n }\n\n instance._lastReadSources = newSet ?? new Set();\n instance._pendingReadSources = undefined;\n instance._currentRenderToken = undefined;\n}\n\nexport function cleanupReadableSubscriptions(\n instance: ComponentInstance\n): void {\n const sources = instance._lastReadSources;\n if (!sources || sources.size === 0) {\n return;\n }\n\n for (const source of sources) {\n source._readers?.delete(instance);\n }\n instance._lastReadSources = new Set();\n}\n\nexport function withDerivedReadTracking<T>(\n subscriber: DerivedSubscriber,\n fn: () => T\n): T {\n const prevDerivedSubscriber = currentDerivedSubscriber;\n currentDerivedSubscriber = subscriber;\n suppressComponentReadTrackingDepth += 1;\n\n try {\n return fn();\n } finally {\n suppressComponentReadTrackingDepth -= 1;\n currentDerivedSubscriber = prevDerivedSubscriber;\n }\n}\n\nexport function syncDerivedDependencySubscriptions(\n subscriber: DerivedSubscriber,\n prevSources: Set<ReadableSource<unknown>>,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n for (const source of prevSources) {\n if (!nextSources.has(source)) {\n source._derivedSubscribers?.delete(subscriber);\n }\n }\n\n for (const source of nextSources) {\n let subscribers = source._derivedSubscribers;\n if (!subscribers) {\n subscribers = new Set();\n source._derivedSubscribers = subscribers;\n }\n subscribers.add(subscriber);\n }\n}\n\nexport function clearDerivedDependencySubscriptions(\n subscriber: DerivedSubscriber,\n sources: Set<ReadableSource<unknown>>\n): void {\n for (const source of sources) {\n source._derivedSubscribers?.delete(subscriber);\n }\n sources.clear();\n}\n\nexport function markReadableDerivedSubscribersDirty(\n source: ReadableSource<unknown>\n): void {\n const subscribers = source._derivedSubscribers;\n if (!subscribers || subscribers.size === 0) {\n return;\n }\n\n for (const subscriber of subscribers) {\n subscriber._markDirty();\n }\n}\n\nexport function markReactivePropsDirtySource(\n source: ReadableSource<unknown>\n): void {\n try {\n (\n globalThis as {\n __ASKR_RENDERER?: RendererBridge;\n }\n ).__ASKR_RENDERER?.markReactivePropsDirtySource?.(source);\n } catch {\n // Keep readable notifications side-effect safe.\n }\n}\n\nexport function notifyReadableReaders(\n source: ReadableSource<unknown>,\n skipInstance?: ComponentInstance | null\n): boolean {\n const readers = source._readers;\n let didScheduleUpdate = false;\n\n if (!readers || readers.size === 0) {\n return false;\n }\n\n for (const [instance, token] of readers) {\n if (skipInstance && instance === skipInstance) {\n continue;\n }\n if (instance.lastRenderToken !== token) {\n continue;\n }\n if (instance.hasPendingUpdate) {\n continue;\n }\n\n instance.hasPendingUpdate = true;\n const task = instance._pendingFlushTask;\n if (task) {\n globalScheduler.enqueue(task);\n } else {\n globalScheduler.enqueue(() => {\n instance.hasPendingUpdate = false;\n instance.notifyUpdate?.();\n });\n }\n didScheduleUpdate = true;\n }\n\n return didScheduleUpdate;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askrjs/askr",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.35",
|
|
4
4
|
"description": "Actor-backed deterministic UI framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"askr",
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@axe-core/playwright": "^4.11.3",
|
|
105
105
|
"@playwright/test": "^1.59.1",
|
|
106
|
-
"@types/node": "^25.6.
|
|
106
|
+
"@types/node": "^25.6.2",
|
|
107
107
|
"jsdom": "^29.1.1",
|
|
108
108
|
"playwright": "^1.59.1",
|
|
109
109
|
"tsd": "^0.33.0",
|