@vobs/router 0.3.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mount.d.ts DELETED
@@ -1,18 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/router
4
- */
5
- import { type PageDefinition, type PageEnvironment, type PageInstance } from '@vobs/runtime-core';
6
- import { type RouteComponent } from './types.js';
7
- export interface MountedRouteChain {
8
- readonly layouts: readonly RouteComponent[];
9
- readonly instances: readonly PageInstance[];
10
- readonly outlets: readonly Element[];
11
- destroy(): void;
12
- }
13
- export declare function mountPageWithLayouts(page: PageDefinition, layouts: readonly RouteComponent[], container: Element, environment: PageEnvironment, cachedLeaf?: PageInstance): Promise<MountedRouteChain>;
14
- export declare function hydratePageWithLayouts(page: PageDefinition, layouts: readonly RouteComponent[], container: Element, environment: PageEnvironment): Promise<MountedRouteChain>;
15
- export declare function createMountedRouteChain(layouts: readonly RouteComponent[], instances: readonly PageInstance[], outlets: readonly Element[]): MountedRouteChain;
16
- export declare function errorLayoutsForFailure(layouts: readonly RouteComponent[], error: unknown): readonly RouteComponent[];
17
- export declare function unwrapRouteMountFailure(error: unknown): unknown;
18
- export declare function destroyPageInstances(instances: readonly PageInstance[]): void;
package/dist/mount.js DELETED
@@ -1,205 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/router
4
- */
5
- import { createRuntimeError, } from '@vobs/runtime-core';
6
- import {} from './types.js';
7
- import { loadRouteComponent } from './resolve.js';
8
- export async function mountPageWithLayouts(page, layouts, container, environment, cachedLeaf) {
9
- if (layouts.length === 0) {
10
- const instance = cachedLeaf ?? (await page.mount(environment));
11
- if (cachedLeaf !== undefined)
12
- cachedLeaf.activate();
13
- container.append(instance.root);
14
- return createMountedRouteChain(layouts, [instance], []);
15
- }
16
- const instances = [];
17
- const outlets = [];
18
- try {
19
- let child;
20
- try {
21
- child = cachedLeaf ?? (await page.mount(environment));
22
- if (cachedLeaf !== undefined)
23
- cachedLeaf.activate();
24
- }
25
- catch (error) {
26
- throw createRoutePageMountFailure(error);
27
- }
28
- instances.push(child);
29
- for (let index = layouts.length - 1; index >= 0; index -= 1) {
30
- const layoutComponent = layouts[index];
31
- if (layoutComponent === undefined)
32
- continue;
33
- try {
34
- const layout = await loadRouteComponent(layoutComponent);
35
- const slottedChild = child;
36
- child = await layout.mount(createLayoutPageEnvironment(environment, (_owner, parent) => {
37
- outlets[index] = parent;
38
- parent.append(slottedChild.root);
39
- }));
40
- }
41
- catch (error) {
42
- throw createRouteLayoutMountFailure(error, index);
43
- }
44
- instances.push(child);
45
- }
46
- container.append(child.root);
47
- return createMountedRouteChain(layouts, [...instances].reverse(), outlets);
48
- }
49
- catch (error) {
50
- destroyPageInstances(instances);
51
- throw error;
52
- }
53
- }
54
- export async function hydratePageWithLayouts(page, layouts, container, environment) {
55
- if (layouts.length === 0) {
56
- const instance = await page.hydrate(container, environment);
57
- return createMountedRouteChain(layouts, [instance], []);
58
- }
59
- const pages = await Promise.all(layouts.map((layout) => loadRouteComponent(layout)));
60
- const chain = await hydratePageChain([...pages, page], 0, container, container, environment);
61
- return createMountedRouteChain(layouts, chain.instances, []);
62
- }
63
- class RoutePageMountFailure extends Error {
64
- error;
65
- kind = 'vobs.route-page-mount-failure';
66
- constructor(error) {
67
- super('Route page mount failed');
68
- this.error = error;
69
- this.name = 'RoutePageMountFailure';
70
- }
71
- }
72
- class RouteLayoutMountFailure extends Error {
73
- error;
74
- layoutIndex;
75
- kind = 'vobs.route-layout-mount-failure';
76
- constructor(error, layoutIndex) {
77
- super('Route layout mount failed');
78
- this.error = error;
79
- this.layoutIndex = layoutIndex;
80
- this.name = 'RouteLayoutMountFailure';
81
- }
82
- }
83
- function createLayoutPageEnvironment(environment, defaultSlot) {
84
- return {
85
- scheduler: environment.scheduler,
86
- security: environment.security,
87
- onError: environment.onError,
88
- ...(environment.components === undefined ? {} : { components: environment.components }),
89
- ...(environment.route === undefined ? {} : { route: environment.route }),
90
- ...(environment.injections === undefined ? {} : { injections: environment.injections }),
91
- slots: {
92
- ...environment.slots,
93
- default: defaultSlot,
94
- },
95
- };
96
- }
97
- async function hydratePageChain(pages, index, container, stateContainer, environment) {
98
- const page = pages[index];
99
- if (page === undefined) {
100
- throw createRuntimeError('VOR603', 'Invalid layout PageDefinition');
101
- }
102
- if (index === pages.length - 1) {
103
- const instance = await page.hydrate(container, environment);
104
- return createMountedRouteChain([], [instance], []);
105
- }
106
- let childChain;
107
- const instance = await page.hydrate(container, createLayoutPageEnvironment(environment, createHydrateLayoutSlot({
108
- hydrateChild(childContainer) {
109
- childChain = hydratePageChain(pages, index + 1, childContainer, stateContainer, environment);
110
- return childChain.then((child) => child.instances[0]);
111
- },
112
- stateContainer,
113
- })));
114
- if (childChain === undefined) {
115
- throw createRuntimeError('VOR605', 'Route layout hydration requires a hydratable slot');
116
- }
117
- const child = await childChain;
118
- return createMountedRouteChain([], [instance, ...child.instances], []);
119
- }
120
- function createHydrateLayoutSlot(options) {
121
- const slot = () => {
122
- throw createRuntimeError('VOR605', 'Route layout hydration requires a hydratable slot');
123
- };
124
- slot.hydrate = (_owner, parent, cursor) => {
125
- void options.hydrateChild(createSlotHydrationContainer(parent, cursor, options.stateContainer));
126
- return cursor + 1;
127
- };
128
- return slot;
129
- }
130
- function createSlotHydrationContainer(parent, cursor, stateContainer) {
131
- let insertionReference = null;
132
- return {
133
- get firstElementChild() {
134
- const node = parent.childNodes[cursor];
135
- return isElementNode(node) ? node : null;
136
- },
137
- querySelectorAll(selector) {
138
- return stateContainer.querySelectorAll(selector);
139
- },
140
- replaceChildren(...nodes) {
141
- const current = parent.childNodes[cursor];
142
- insertionReference = current?.nextSibling ?? null;
143
- current?.remove();
144
- appendSlotNodes(parent, insertionReference, nodes);
145
- },
146
- append(...nodes) {
147
- appendSlotNodes(parent, insertionReference, nodes);
148
- },
149
- };
150
- }
151
- function appendSlotNodes(parent, reference, nodes) {
152
- for (const node of nodes) {
153
- parent.insertBefore(typeof node === 'string' ? document.createTextNode(node) : node, reference);
154
- }
155
- }
156
- function isElementNode(node) {
157
- return node?.nodeType === 1;
158
- }
159
- export function createMountedRouteChain(layouts, instances, outlets) {
160
- if (instances[0]?.root === undefined) {
161
- throw createRuntimeError('VOR603', 'Invalid layout PageInstance');
162
- }
163
- return {
164
- layouts,
165
- instances,
166
- outlets,
167
- destroy() {
168
- destroyPageInstances([...instances].reverse());
169
- },
170
- };
171
- }
172
- function createRoutePageMountFailure(error) {
173
- return new RoutePageMountFailure(error);
174
- }
175
- function createRouteLayoutMountFailure(error, layoutIndex) {
176
- return new RouteLayoutMountFailure(error, layoutIndex);
177
- }
178
- export function errorLayoutsForFailure(layouts, error) {
179
- const failure = readRouteLayoutMountFailure(error);
180
- return failure === undefined ? layouts : layouts.slice(0, failure.layoutIndex);
181
- }
182
- export function unwrapRouteMountFailure(error) {
183
- return (readRoutePageMountFailure(error)?.error ?? readRouteLayoutMountFailure(error)?.error ?? error);
184
- }
185
- function readRoutePageMountFailure(error) {
186
- return error instanceof RoutePageMountFailure ? error : undefined;
187
- }
188
- function readRouteLayoutMountFailure(error) {
189
- return error instanceof RouteLayoutMountFailure ? error : undefined;
190
- }
191
- export function destroyPageInstances(instances) {
192
- // A single page destroy failure must not interrupt the rest (avoids chained leaks); errors are aggregated and thrown together.
193
- const errors = [];
194
- for (const instance of instances) {
195
- try {
196
- instance.destroy();
197
- }
198
- catch (error) {
199
- errors.push(error);
200
- }
201
- }
202
- if (errors.length > 0) {
203
- throw new AggregateError(errors, 'Destroy page instances failed');
204
- }
205
- }
@@ -1,9 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/router
4
- */
5
- import { type PageSetupContext } from '@vobs/runtime-core';
6
- import { type CollectRouteNavigationOptions, type RouteLocation, type RouteNavigationItem, type RouteNavigationScope, type RouteNavigationScopeOptions, type RouteRecord } from './types.js';
7
- export declare function collectRouteNavigation(routes: readonly RouteRecord[], options?: CollectRouteNavigationOptions): readonly RouteNavigationItem[];
8
- export declare function resolveActiveRouteNavigationId(route: RouteLocation, items: readonly RouteNavigationItem[], fallback?: string): string | undefined;
9
- export declare function createRouteNavigationScope(context: PageSetupContext, options?: RouteNavigationScopeOptions): RouteNavigationScope;
@@ -1,95 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/router
4
- */
5
- import { computed, signal } from '@vobs/reactivity';
6
- import {} from '@vobs/runtime-core';
7
- import { CurrentRouteKey, RouteRecordsKey, } from './types.js';
8
- import { isNestedRouteRecord, joinRouteRecordPath } from './match.js';
9
- export function collectRouteNavigation(routes, options = {}) {
10
- const area = options.area;
11
- const defaultArea = options.defaultArea ?? 'default';
12
- return [...collectRouteNavigationItems(routes, { area, defaultArea, parentPath: '' })].sort((left, right) => left.order - right.order || left.label.localeCompare(right.label));
13
- }
14
- export function resolveActiveRouteNavigationId(route, items, fallback) {
15
- const activeNav = route.meta?.activeNav;
16
- if (typeof activeNav === 'string' && hasRouteNavigationItem(items, activeNav))
17
- return activeNav;
18
- const nav = readRouteNavigationMeta(route.meta?.nav);
19
- if (nav !== undefined && hasRouteNavigationItem(items, nav.id))
20
- return nav.id;
21
- const matched = items.find((item) => route.path === item.href || route.path.startsWith(`${item.href}/`));
22
- return matched?.id ?? fallback;
23
- }
24
- export function createRouteNavigationScope(context, options = {}) {
25
- const currentRoute = context.maybeInject(CurrentRouteKey) ?? signal(context.route);
26
- const routeRecords = context.inject(RouteRecordsKey, () => []);
27
- const route = computed(() => currentRoute.value ?? context.route);
28
- const items = computed(() => collectRouteNavigation(routeRecords, options));
29
- const activeId = computed(() => resolveActiveRouteNavigationId(route.value, items.value, options.activeFallback));
30
- return {
31
- route,
32
- items,
33
- activeId,
34
- title: computed(() => readRouteMetaString(route.value.meta, 'title') ?? options.titleFallback ?? ''),
35
- description: computed(() => readRouteMetaString(route.value.meta, 'description') ?? options.descriptionFallback ?? ''),
36
- status: computed(() => readRouteMetaString(route.value.meta, 'status') ?? options.statusFallback ?? ''),
37
- };
38
- }
39
- function collectRouteNavigationItems(routes, state) {
40
- return routes.flatMap((route) => {
41
- const href = joinRouteRecordPath(state.parentPath, route.path);
42
- const nav = readRouteNavigationMeta(route.meta?.nav);
43
- const items = [];
44
- if (nav !== undefined) {
45
- const area = nav.area ?? state.defaultArea;
46
- if (state.area === undefined || state.area === area) {
47
- items.push({
48
- id: nav.id,
49
- label: nav.label ?? readRouteMetaString(route.meta, 'title') ?? nav.id,
50
- href,
51
- area,
52
- order: nav.order ?? 0,
53
- state: nav.state ?? 'ready',
54
- meta: route.meta ?? {},
55
- ...(nav.icon === undefined ? {} : { icon: nav.icon }),
56
- });
57
- }
58
- }
59
- if (isNestedRouteRecord(route)) {
60
- items.push(...collectRouteNavigationItems(route.children, {
61
- area: state.area,
62
- defaultArea: state.defaultArea,
63
- parentPath: href,
64
- }));
65
- }
66
- return items;
67
- });
68
- }
69
- function readRouteNavigationMeta(nav) {
70
- if (typeof nav !== 'object' || nav === null)
71
- return undefined;
72
- const id = nav.id;
73
- if (typeof id !== 'string')
74
- return undefined;
75
- const label = nav.label;
76
- const icon = nav.icon;
77
- const area = nav.area;
78
- const order = nav.order;
79
- const state = nav.state;
80
- return {
81
- id,
82
- ...(typeof label === 'string' ? { label } : {}),
83
- ...(typeof icon === 'string' ? { icon } : {}),
84
- ...(typeof area === 'string' ? { area } : {}),
85
- ...(typeof order === 'number' ? { order } : {}),
86
- ...(typeof state === 'string' ? { state } : {}),
87
- };
88
- }
89
- function readRouteMetaString(meta, key) {
90
- const value = meta?.[key];
91
- return typeof value === 'string' ? value : undefined;
92
- }
93
- function hasRouteNavigationItem(items, id) {
94
- return items.some((item) => item.id === id);
95
- }
package/dist/resolve.d.ts DELETED
@@ -1,27 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/router
4
- */
5
- import { type PageDefinition, type RouteResolver } from '@vobs/runtime-core';
6
- import { type ResolvedRoute, type ResolveRouteGuardOptions, type ResolveRouteInitialStateOptions, type ResolveRouteOptions, type RouteComponent, type RouteLoaderCache, type RouteLoaderCachePolicy, type RouteLocation } from './types.js';
7
- export declare const defaultRedirectLimit = 8;
8
- export declare function resolveRoute(options: ResolveRouteOptions): ResolvedRoute;
9
- export declare function resolveRouteGuard(route: ResolvedRoute, options?: ResolveRouteGuardOptions): string | undefined | Promise<string | undefined>;
10
- export declare function resolveRouteInitialState(route: ResolvedRoute, options?: ResolveRouteInitialStateOptions): unknown;
11
- export interface RouteLoaderCacheOptions {
12
- /**
13
- * Max entries; the least recently used entry is evicted when exceeded.
14
- * Defaults to 100 so dynamic routes (/user/:id) cannot accumulate one entry per path.
15
- */
16
- readonly max?: number;
17
- }
18
- export declare function createRouteLoaderCache(options?: RouteLoaderCacheOptions): RouteLoaderCache;
19
- export declare function loadRouteComponent(component: RouteComponent): Promise<PageDefinition>;
20
- export declare function readLoaderCacheKey(policy: RouteLoaderCachePolicy | undefined, route: RouteLocation, options: ResolveRouteInitialStateOptions): string | undefined;
21
- /**
22
- * Adapter for the RouteResolver contract: maps @vobs/router's pure resolve functions
23
- * to the Core-defined SSR resolution contract for consumers like server-renderer,
24
- * keeping the framework core independent of plugin implementations
25
- * (dependency direction: server-renderer → contract ← router adapter).
26
- */
27
- export declare function createRouteResolver(): RouteResolver;
package/dist/resolve.js DELETED
@@ -1,272 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/router
4
- */
5
- import { createInjectionScope, createRuntimeError, runWithInjectionScope, } from '@vobs/runtime-core';
6
- import {} from './types.js';
7
- import { resolveRouteMatch } from './match.js';
8
- import { createRouteLocation } from './location.js';
9
- export const defaultRedirectLimit = 8;
10
- const routeComponentCache = new WeakMap();
11
- const pendingLoaderSignals = new WeakMap();
12
- export function resolveRoute(options) {
13
- const match = resolveRouteMatch(options.routes, options.path, options.redirectLimit ?? defaultRedirectLimit, 0);
14
- const component = match?.component ?? options.notFound;
15
- const location = match?.location ?? createRouteLocation(options.path);
16
- if (component === undefined) {
17
- throw createRuntimeError('VOR601', `Route not found: ${options.path}`);
18
- }
19
- return {
20
- status: match === undefined ? 'notFound' : 'matched',
21
- route: location,
22
- component,
23
- ...(match?.layouts === undefined ? {} : { layouts: match.layouts }),
24
- ...(match?.error === undefined ? {} : { error: match.error }),
25
- ...(match?.meta === undefined ? {} : { meta: match.meta }),
26
- ...(match?.guard === undefined ? {} : { guard: match.guard }),
27
- ...(match?.initialState === undefined ? {} : { initialState: match.initialState }),
28
- ...(match?.loader === undefined ? {} : { loader: match.loader }),
29
- ...(match?.loaderCache === undefined ? {} : { loaderCache: match.loaderCache }),
30
- };
31
- }
32
- export function resolveRouteGuard(route, options = {}) {
33
- if (route.guard === undefined)
34
- return undefined;
35
- const context = createRouteGuardContext(route.route, options);
36
- const result = runWithInjectionScope(context.injections, () => route.guard(context));
37
- if (isPromiseLike(result)) {
38
- return result.then((value) => readGuardRedirect(route.route, value));
39
- }
40
- return readGuardRedirect(route.route, result);
41
- }
42
- export function resolveRouteInitialState(route, options = {}) {
43
- if (route.loader === undefined)
44
- return route.initialState;
45
- const context = createRouteLoaderContext(route.route, options);
46
- const cacheKey = readLoaderCacheKey(route.loaderCache, route.route, options);
47
- if (cacheKey !== undefined && options.loaderCache?.has(cacheKey) === true) {
48
- const cached = options.loaderCache.get(cacheKey);
49
- if (!isPromiseLike(cached))
50
- return cached;
51
- // A pending loader may belong to a superseded navigation. Keep prefetch deduplication,
52
- // but do not hand a cancelled navigation's request to a new consumer.
53
- if (pendingLoaderSignals.get(cached) === undefined ||
54
- !pendingLoaderSignals.get(cached)?.aborted) {
55
- return cached;
56
- }
57
- options.loaderCache.delete(cacheKey);
58
- }
59
- const loaded = runWithInjectionScope(context.injections, () => route.loader(context));
60
- return cacheLoaderResult(loaded, cacheKey, context.signal, options.loaderCache);
61
- }
62
- export function createRouteLoaderCache(options = {}) {
63
- const max = options.max ?? 100;
64
- const entries = new Map();
65
- const touch = (key) => {
66
- const value = entries.get(key);
67
- if (value !== undefined) {
68
- entries.delete(key);
69
- entries.set(key, value);
70
- }
71
- };
72
- const evict = () => {
73
- while (entries.size > max) {
74
- const oldest = entries.keys().next().value;
75
- if (oldest === undefined)
76
- break;
77
- entries.delete(oldest);
78
- }
79
- };
80
- return {
81
- has(key) {
82
- return entries.has(key);
83
- },
84
- get(key) {
85
- const value = entries.get(key);
86
- if (value !== undefined)
87
- touch(key);
88
- return value;
89
- },
90
- set(key, value) {
91
- entries.set(key, value);
92
- evict();
93
- },
94
- delete(key) {
95
- return entries.delete(key);
96
- },
97
- clear() {
98
- entries.clear();
99
- },
100
- };
101
- }
102
- export async function loadRouteComponent(component) {
103
- const page = typeof component === 'function' ? await loadLazyRouteComponentCached(component) : component;
104
- if (page?.kind !== 'vobs.page' || typeof page.mount !== 'function') {
105
- throw createRuntimeError('VOR603', 'Invalid PageDefinition');
106
- }
107
- return page;
108
- }
109
- function loadLazyRouteComponentCached(component) {
110
- const cached = routeComponentCache.get(component);
111
- if (cached !== undefined)
112
- return cached;
113
- const loaded = component().then((module) => module.default, (error) => {
114
- routeComponentCache.delete(component);
115
- throw error;
116
- });
117
- routeComponentCache.set(component, loaded);
118
- return loaded;
119
- }
120
- function readRouteInjectionScope(options) {
121
- return options.injections ?? createInjectionScope();
122
- }
123
- function createRouteInjectionContext(injections) {
124
- return {
125
- injections,
126
- maybeInject(key) {
127
- return injections.maybeInject(key);
128
- },
129
- inject(key, fallback) {
130
- return arguments.length === 1
131
- ? injections.inject(key)
132
- : injections.inject(key, fallback);
133
- },
134
- };
135
- }
136
- function createRouteLoaderContext(route, options) {
137
- const injections = readRouteInjectionScope(options);
138
- return {
139
- route,
140
- signal: options.signal ?? new AbortController().signal,
141
- ...(options.request === undefined ? {} : { request: options.request }),
142
- ...createRouteInjectionContext(injections),
143
- };
144
- }
145
- function createRouteGuardContext(route, options) {
146
- const injections = readRouteInjectionScope(options);
147
- return {
148
- route,
149
- signal: options.signal ?? new AbortController().signal,
150
- ...(options.request === undefined ? {} : { request: options.request }),
151
- ...createRouteInjectionContext(injections),
152
- };
153
- }
154
- function readGuardRedirect(route, result) {
155
- if (result === false) {
156
- throw createRuntimeError('VOR606', `Route navigation blocked: ${route.path}`);
157
- }
158
- if (typeof result === 'string')
159
- return result;
160
- if (typeof result === 'object' && result !== null)
161
- return result.redirect;
162
- return undefined;
163
- }
164
- export function readLoaderCacheKey(policy, route, options) {
165
- if (policy === undefined || policy === false || options.loaderCache === undefined)
166
- return undefined;
167
- if (options.request !== undefined)
168
- return undefined;
169
- const key = typeof policy === 'object' ? policy.key : undefined;
170
- if (typeof key === 'function')
171
- return key(route);
172
- if (typeof key === 'string')
173
- return key;
174
- return route.path;
175
- }
176
- function cacheLoaderResult(loaded, cacheKey, signal, loaderCache) {
177
- if (isPromiseLike(loaded)) {
178
- const pending = loaded.then((value) => {
179
- if (cacheKey !== undefined && loaderCache?.get(cacheKey) === pending) {
180
- if (signal.aborted) {
181
- loaderCache.delete(cacheKey);
182
- }
183
- else {
184
- loaderCache.set(cacheKey, value);
185
- }
186
- }
187
- else {
188
- writeLoaderCache(cacheKey, value, signal, loaderCache);
189
- }
190
- return value;
191
- }, (error) => {
192
- if (cacheKey !== undefined && loaderCache?.get(cacheKey) === pending) {
193
- loaderCache.delete(cacheKey);
194
- }
195
- throw error;
196
- });
197
- pendingLoaderSignals.set(pending, signal);
198
- writeLoaderCache(cacheKey, pending, signal, loaderCache);
199
- return pending;
200
- }
201
- writeLoaderCache(cacheKey, loaded, signal, loaderCache);
202
- return loaded;
203
- }
204
- function writeLoaderCache(cacheKey, value, signal, loaderCache) {
205
- if (cacheKey === undefined || signal.aborted || loaderCache === undefined)
206
- return;
207
- loaderCache.set(cacheKey, value);
208
- }
209
- function isPromiseLike(value) {
210
- return (typeof value === 'object' &&
211
- value !== null &&
212
- 'then' in value &&
213
- typeof value.then === 'function');
214
- }
215
- /**
216
- * Adapter for the RouteResolver contract: maps @vobs/router's pure resolve functions
217
- * to the Core-defined SSR resolution contract for consumers like server-renderer,
218
- * keeping the framework core independent of plugin implementations
219
- * (dependency direction: server-renderer → contract ← router adapter).
220
- */
221
- export function createRouteResolver() {
222
- return {
223
- resolve(options) {
224
- const resolved = resolveRoute({
225
- routes: options.routes,
226
- path: options.path,
227
- ...(options.notFound === undefined ? {} : { notFound: options.notFound }),
228
- ...(options.error === undefined ? {} : { error: options.error }),
229
- ...(options.redirectLimit === undefined ? {} : { redirectLimit: options.redirectLimit }),
230
- });
231
- return toRouteResolution(resolved);
232
- },
233
- resolveGuard(resolution, options) {
234
- return resolveRouteGuard(resolution, {
235
- ...(options.signal === undefined ? {} : { signal: options.signal }),
236
- ...(options.request === undefined ? {} : { request: options.request }),
237
- ...(options.injections === undefined
238
- ? {}
239
- : { injections: options.injections }),
240
- });
241
- },
242
- resolveInitialState(resolution, options) {
243
- return resolveRouteInitialState(resolution, {
244
- ...(options.signal === undefined ? {} : { signal: options.signal }),
245
- ...(options.request === undefined ? {} : { request: options.request }),
246
- ...(options.loaderCache === undefined
247
- ? {}
248
- : { loaderCache: options.loaderCache }),
249
- ...(options.injections === undefined
250
- ? {}
251
- : { injections: options.injections }),
252
- });
253
- },
254
- loadComponent(component) {
255
- return loadRouteComponent(component);
256
- },
257
- };
258
- }
259
- function toRouteResolution(resolved) {
260
- return {
261
- status: resolved.status,
262
- route: resolved.route,
263
- component: resolved.component,
264
- ...(resolved.layouts === undefined ? {} : { layouts: resolved.layouts }),
265
- ...(resolved.error === undefined ? {} : { error: resolved.error }),
266
- ...(resolved.initialState === undefined ? {} : { initialState: resolved.initialState }),
267
- ...(resolved.guard === undefined ? {} : { guard: resolved.guard }),
268
- ...(resolved.loader === undefined ? {} : { loader: resolved.loader }),
269
- ...(resolved.loaderCache === undefined ? {} : { loaderCache: resolved.loaderCache }),
270
- ...(resolved.meta === undefined ? {} : { meta: resolved.meta }),
271
- };
272
- }
package/dist/router.d.ts DELETED
@@ -1,8 +0,0 @@
1
- /** @license MIT
2
- * Copyright (c) 2026 vobsjs
3
- * @vobs/router
4
- */
5
- import { type RouteRecord, type ValidatedRouteRecords, type Router, type RouterOptions } from './types.js';
6
- export declare function createRouter<const Routes extends readonly RouteRecord[]>(options: RouterOptions<Routes> & {
7
- readonly routes: Routes & ValidatedRouteRecords<Routes>;
8
- }): Router;