@analogjs/router 3.0.0-alpha.7 → 3.0.0-alpha.70
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/content/package.json +4 -0
- package/fesm2022/analogjs-router-content.mjs +63 -0
- package/fesm2022/analogjs-router-content.mjs.map +1 -0
- package/fesm2022/analogjs-router-i18n.mjs +156 -0
- package/fesm2022/analogjs-router-i18n.mjs.map +1 -0
- package/fesm2022/analogjs-router-server-actions.mjs +2 -27
- package/fesm2022/analogjs-router-server.mjs +734 -105
- package/fesm2022/analogjs-router-server.mjs.map +1 -0
- package/fesm2022/analogjs-router-tanstack-query-server.mjs +71 -0
- package/fesm2022/analogjs-router-tanstack-query-server.mjs.map +1 -0
- package/fesm2022/analogjs-router-tanstack-query.mjs +39 -0
- package/fesm2022/analogjs-router-tanstack-query.mjs.map +1 -0
- package/fesm2022/analogjs-router-tokens.mjs +7 -2
- package/fesm2022/analogjs-router-tokens.mjs.map +1 -0
- package/fesm2022/analogjs-router.mjs +670 -170
- package/fesm2022/analogjs-router.mjs.map +1 -0
- package/fesm2022/debug.page.mjs +53 -31
- package/fesm2022/debug.page.mjs.map +1 -0
- package/fesm2022/provide-analog-query.mjs +72 -0
- package/fesm2022/provide-analog-query.mjs.map +1 -0
- package/fesm2022/route-files.mjs +361 -0
- package/fesm2022/route-files.mjs.map +1 -0
- package/fesm2022/routes.mjs +5 -278
- package/fesm2022/routes.mjs.map +1 -0
- package/fesm2022/src.mjs +335 -0
- package/fesm2022/src.mjs.map +1 -0
- package/i18n/package.json +4 -0
- package/package.json +52 -5
- package/tanstack-query/package.json +4 -0
- package/tanstack-query/server/package.json +4 -0
- package/types/content/src/index.d.ts +4 -0
- package/types/content/src/lib/debug/routes.d.ts +10 -0
- package/types/{src → content/src}/lib/markdown-helpers.d.ts +1 -1
- package/types/content/src/lib/routes.d.ts +8 -0
- package/types/content/src/lib/with-content-routes.d.ts +2 -0
- package/types/i18n/src/index.d.ts +1 -0
- package/types/i18n/src/provide-i18n.d.ts +92 -0
- package/types/server/actions/src/define-action.d.ts +54 -0
- package/types/server/actions/src/define-api-route.d.ts +57 -0
- package/types/server/actions/src/define-page-load.d.ts +55 -0
- package/types/server/actions/src/define-server-route.d.ts +68 -0
- package/types/server/actions/src/index.d.ts +9 -1
- package/types/server/actions/src/parse-request-data.d.ts +9 -0
- package/types/server/actions/src/validate.d.ts +8 -0
- package/types/server/src/defer-reconcile-runtime.d.ts +23 -0
- package/types/server/src/index.d.ts +9 -2
- package/types/server/src/provide-server-context.d.ts +15 -1
- package/types/server/src/render-stream.d.ts +40 -0
- package/types/server/src/render.d.ts +3 -3
- package/types/server/src/server-fn/app-injector.d.ts +30 -0
- package/types/server/src/server-fn/dispatch.d.ts +56 -0
- package/types/server/src/server-fn/event-handler.d.ts +22 -0
- package/types/server/src/server-fn/interceptors.d.ts +30 -0
- package/types/server/src/server-fn/node-context.d.ts +14 -0
- package/types/server/src/server-fn/registry.d.ts +7 -0
- package/types/server/src/server-fn/same-origin.d.ts +46 -0
- package/types/server/src/server-fn/server-fn.d.ts +21 -0
- package/types/server/src/server-fn/ssr-dispatcher.d.ts +17 -0
- package/types/server/src/utils/reset-component-def-tviews.d.ts +14 -0
- package/types/server/src/utils/stream-html.d.ts +13 -0
- package/types/server/src/utils/stream-request.d.ts +24 -0
- package/types/src/index.d.ts +20 -6
- package/types/src/lib/cache-key.d.ts +1 -1
- package/types/src/lib/cookie-interceptor.d.ts +1 -1
- package/types/src/lib/debug/debug.page.d.ts +4 -2
- package/types/src/lib/define-route.d.ts +6 -1
- package/types/src/lib/endpoints.d.ts +1 -1
- package/types/src/lib/experimental.d.ts +140 -0
- package/types/src/lib/form-action.directive.d.ts +12 -5
- package/types/src/lib/inject-load.d.ts +5 -2
- package/types/src/lib/inject-navigate.d.ts +23 -0
- package/types/src/lib/inject-route-context.d.ts +32 -0
- package/types/src/lib/inject-typed-params.d.ts +63 -0
- package/types/src/lib/json-ld.d.ts +32 -0
- package/types/src/lib/meta-tags.d.ts +3 -1
- package/types/src/lib/models.d.ts +3 -0
- package/types/src/lib/provide-file-router-base.d.ts +4 -0
- package/types/src/lib/provide-file-router.d.ts +2 -8
- package/types/src/lib/route-builder.d.ts +5 -0
- package/types/src/lib/route-files.d.ts +18 -0
- package/types/src/lib/route-path.d.ts +124 -0
- package/types/src/lib/route-types.d.ts +2 -1
- package/types/src/lib/routes.d.ts +2 -10
- package/types/src/lib/server-fn/dispatcher.d.ts +23 -0
- package/types/src/lib/server-fn/inject-server-fn.d.ts +44 -0
- package/types/src/lib/server-fn/server-fn-ref.d.ts +24 -0
- package/types/src/lib/server-fn/types.d.ts +55 -0
- package/types/src/lib/validation-errors.d.ts +7 -0
- package/types/tanstack-query/server/src/define-page-load-queries.d.ts +66 -0
- package/types/tanstack-query/server/src/index.d.ts +3 -0
- package/types/tanstack-query/src/constants.d.ts +9 -0
- package/types/tanstack-query/src/index.d.ts +2 -0
- package/types/tanstack-query/src/provide-analog-query.d.ts +4 -0
- package/types/tanstack-query/src/provide-server-analog-query.d.ts +2 -0
- package/types/tanstack-query/src/server-query.d.ts +16 -0
- package/types/tokens/src/index.d.ts +2 -0
- package/types/server/src/server-component-render.d.ts +0 -4
- package/types/server/src/tokens.d.ts +0 -7
- package/types/src/lib/server.component.d.ts +0 -33
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StaticProvider } from '@angular/core';
|
|
2
|
-
import { ServerInternalFetch, ServerRequest, ServerResponse } from '
|
|
2
|
+
import { ServerInternalFetch, ServerRequest, ServerResponse } from '../../tokens/src/index.js';
|
|
3
3
|
export declare function provideServerContext({ req, res, fetch, }: {
|
|
4
4
|
req: ServerRequest;
|
|
5
5
|
res: ServerResponse;
|
|
@@ -9,3 +9,17 @@ export declare function getBaseUrl(req: ServerRequest): string;
|
|
|
9
9
|
export declare function getRequestProtocol(req: ServerRequest, opts?: {
|
|
10
10
|
xForwardedProto?: boolean;
|
|
11
11
|
}): string;
|
|
12
|
+
/**
|
|
13
|
+
* Detects the locale from the request URL path prefix or Accept-Language header.
|
|
14
|
+
* URL prefix takes priority (e.g. /fr/about -> 'fr').
|
|
15
|
+
*/
|
|
16
|
+
export declare function detectLocale(req: ServerRequest): string | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Extracts a locale from the first URL path segment if it matches
|
|
19
|
+
* a BCP 47-like pattern (e.g. 'en', 'en-US', 'zh-Hans-CN').
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractLocaleFromUrl(url: string): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Parses the Accept-Language header and returns the most preferred language.
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseAcceptLanguage(header: string | undefined): string | undefined;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progressive streaming SSR renderer — EXPERIMENTAL.
|
|
3
|
+
*
|
|
4
|
+
* Returns a `ReadableStream<Uint8Array>` that flushes bytes DURING the render,
|
|
5
|
+
* not after it:
|
|
6
|
+
* 1. the document head + a client reconcile runtime are flushed immediately,
|
|
7
|
+
* before the app has finished rendering, so the browser starts fetching
|
|
8
|
+
* assets right away;
|
|
9
|
+
* 2. each `@defer (hydrate …)` block's content is flushed the moment it
|
|
10
|
+
* resolves on the server — out of document order — while later blocks are
|
|
11
|
+
* still pending (proven: a slow block does not hold back an early one);
|
|
12
|
+
* 3. once the app is stable, the authoritative, fully hydration-annotated
|
|
13
|
+
* document is flushed as the tail. This is byte-identical to a buffered
|
|
14
|
+
* `renderApplication`, and is what Angular's incremental hydration runs
|
|
15
|
+
* against on the client.
|
|
16
|
+
*
|
|
17
|
+
* Unlike a buffered renderer, this drives the platform directly
|
|
18
|
+
* (`platformServer` + `bootstrapApplication` + `ɵrenderInternal`) so it can
|
|
19
|
+
* interleave flushes with rendering. Angular's hydration annotation is
|
|
20
|
+
* whole-document (the root's `ngh` index references every `@defer` container),
|
|
21
|
+
* so the authoritative hydration payload is necessarily the tail: RENDERING
|
|
22
|
+
* streams progressively, and hydration begins once the tail arrives.
|
|
23
|
+
*
|
|
24
|
+
* Depends on an upstream Angular per-block resolution hook exposed on two
|
|
25
|
+
* globals (see {@link SsrStreamingGlobals}). When the primitive is absent,
|
|
26
|
+
* `renderStream` degrades to a single buffered chunk so behaviour matches the
|
|
27
|
+
* classic `render()` path, which is unchanged and remains the default.
|
|
28
|
+
*/
|
|
29
|
+
import { ApplicationConfig, Provider, Type } from '@angular/core';
|
|
30
|
+
import type { ServerContext } from '@analogjs/router/tokens';
|
|
31
|
+
/**
|
|
32
|
+
* Returns a function that renders a URL to a `ReadableStream<Uint8Array>`.
|
|
33
|
+
*
|
|
34
|
+
* Usage in main.server.ts:
|
|
35
|
+
* ```ts
|
|
36
|
+
* import { renderStream } from '@analogjs/router/server';
|
|
37
|
+
* export default renderStream(App, config);
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function renderStream(rootComponent: Type<unknown>, config: ApplicationConfig, platformProviders?: Provider[]): (url: string, document: string, serverContext: ServerContext) => Promise<ReadableStream<Uint8Array>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ApplicationConfig, Provider, Type } from '@angular/core';
|
|
2
|
-
import type { ServerContext } from '
|
|
2
|
+
import type { ServerContext } from '../../tokens/src/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Returns a function that accepts the navigation URL,
|
|
5
5
|
* the root HTML, and server context.
|
|
@@ -7,6 +7,6 @@ import type { ServerContext } from '@analogjs/router/tokens';
|
|
|
7
7
|
* @param rootComponent
|
|
8
8
|
* @param config
|
|
9
9
|
* @param platformProviders
|
|
10
|
-
* @returns Promise<string
|
|
10
|
+
* @returns Promise<string>
|
|
11
11
|
*/
|
|
12
|
-
export declare function render(rootComponent: Type<unknown>, config: ApplicationConfig, platformProviders?: Provider[]): (url: string, document: string, serverContext: ServerContext) => Promise<string
|
|
12
|
+
export declare function render(rootComponent: Type<unknown>, config: ApplicationConfig, platformProviders?: Provider[]): (url: string, document: string, serverContext: ServerContext) => Promise<string>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ApplicationConfig, Injector, type StaticProvider } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* Builds the parent injector the server-function dispatch endpoint runs handlers
|
|
4
|
+
* against, over HTTP.
|
|
5
|
+
*
|
|
6
|
+
* A plain `Injector.create({ providers })` resolves explicitly-listed providers
|
|
7
|
+
* but not tree-shakeable `providedIn: 'root'` services — those attach to a
|
|
8
|
+
* *bootstrapped* application's root injector, which `Injector.create` is not.
|
|
9
|
+
* So the in-process SSR leg (whose parent is the app's own bootstrapped
|
|
10
|
+
* injector) resolved `root` services while the HTTP leg did not — the same
|
|
11
|
+
* handler could work while rendering and fail when called from the browser.
|
|
12
|
+
*
|
|
13
|
+
* Bootstrapping a real application on the server platform closes that gap: the
|
|
14
|
+
* returned `appRef.injector` is a root environment injector, so both listed
|
|
15
|
+
* providers and `providedIn: 'root'` services resolve, matching SSR.
|
|
16
|
+
*
|
|
17
|
+
* The generated endpoint passes the app's own server `ApplicationConfig` (the
|
|
18
|
+
* one `main.server.ts` renders with), so a handler sees exactly the DI the app
|
|
19
|
+
* configured — services, tokens, and interceptors alike — with no second
|
|
20
|
+
* provider list to keep in sync. No root component is bootstrapped
|
|
21
|
+
* (`createApplication`, not `bootstrapApplication`), so nothing renders, no
|
|
22
|
+
* change detection runs, and the router registers but never navigates. It is a
|
|
23
|
+
* DI container with the app's providers, built once and reused for the process,
|
|
24
|
+
* with only `REQUEST`/`RESPONSE` rebuilt per call in the child.
|
|
25
|
+
*
|
|
26
|
+
* A bare provider array is also accepted (direct callers and tests without an
|
|
27
|
+
* app config); it is wrapped with `provideServerRendering` so the server tokens
|
|
28
|
+
* resolve the same way.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createServerFnAppInjector(configOrProviders?: ApplicationConfig | StaticProvider[]): Promise<Injector>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Injector, type StaticProvider } from '@angular/core';
|
|
2
|
+
import type { H3Event } from 'nitro/h3';
|
|
3
|
+
export interface DispatchResult {
|
|
4
|
+
status: number;
|
|
5
|
+
body: unknown;
|
|
6
|
+
/**
|
|
7
|
+
* Headers from a returned `Response` (`fail`/`redirect`): Location, … The
|
|
8
|
+
* value is an array when the header legitimately repeats, which is why
|
|
9
|
+
* `Set-Cookie` is read separately below — collapsing several cookies into one
|
|
10
|
+
* comma-joined value corrupts them.
|
|
11
|
+
*/
|
|
12
|
+
headers?: Record<string, string | string[]>;
|
|
13
|
+
}
|
|
14
|
+
export interface DispatchServerFnOptions {
|
|
15
|
+
/**
|
|
16
|
+
* The app's environment injector. The per-request injector is created as its
|
|
17
|
+
* child, so handlers resolve app services (and `providedIn: 'root'` services,
|
|
18
|
+
* when this is the app's bootstrapped injector) and registered interceptors
|
|
19
|
+
* without re-listing them per request.
|
|
20
|
+
*/
|
|
21
|
+
parent?: Injector;
|
|
22
|
+
/** Extra per-request providers, for direct callers without an app injector. */
|
|
23
|
+
providers?: StaticProvider[];
|
|
24
|
+
/** Request HTTP method; enforced against the function's configured method. */
|
|
25
|
+
method?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Origins permitted beyond same-origin, merged with any registered through DI
|
|
28
|
+
* (`provideServerFns(withAllowedOrigins([...]))`). The transport is
|
|
29
|
+
* same-origin by default (cross-origin browser calls are rejected with 403);
|
|
30
|
+
* `'*'` disables the check entirely. Only consulted for HTTP-transport calls
|
|
31
|
+
* (those that pass `method`).
|
|
32
|
+
*/
|
|
33
|
+
allowedOrigins?: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Server-side dispatch for a server function call.
|
|
37
|
+
*
|
|
38
|
+
* 1. reject cross-origin browser calls (403), unless allow-listed — HTTP
|
|
39
|
+
* transport only (in-process callers omit `method` and are exempt)
|
|
40
|
+
* 2. look up the function by id
|
|
41
|
+
* 3. enforce the configured HTTP method (405 on mismatch)
|
|
42
|
+
* 4. require a JSON body on input-bearing calls (415 otherwise)
|
|
43
|
+
* 5. validate `input` against the Standard-Schema (4xx on failure)
|
|
44
|
+
* 6. build a per-request injector (REQUEST/RESPONSE + app providers)
|
|
45
|
+
* 7. run the interceptor chain, then the handler, re-entering
|
|
46
|
+
* `runInInjectionContext` at every hop so `inject()` works even after an
|
|
47
|
+
* interceptor `await`s before calling `next`
|
|
48
|
+
* 8. a `Response` returned by an interceptor/handler (`fail`/`redirect`)
|
|
49
|
+
* short-circuits with its status AND headers
|
|
50
|
+
*
|
|
51
|
+
* `options.method` is the request's HTTP method; when provided it is enforced
|
|
52
|
+
* against the function's configured method AND it turns on the same-origin
|
|
53
|
+
* guard. Transports (the generated Nitro handler) always pass it; trusted
|
|
54
|
+
* in-process callers may omit it, which also exempts them from the origin guard.
|
|
55
|
+
*/
|
|
56
|
+
export declare function dispatchServerFn(id: string, rawInput: unknown, event: Pick<H3Event, 'node'>, options?: DispatchServerFnOptions): Promise<DispatchResult>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Injector } from '@angular/core';
|
|
2
|
+
import { type EventHandler, type H3Event } from 'nitro/h3';
|
|
3
|
+
/**
|
|
4
|
+
* The h3 request/response layer for the server-function dispatch route.
|
|
5
|
+
*
|
|
6
|
+
* `createServerFnAppInjector` bootstraps the parent injector once; this wraps
|
|
7
|
+
* that in the `/_analog/fn/:id` handler the Nitro build registers. Kept as a
|
|
8
|
+
* runtime function (rather than inlined into the generated module) so the
|
|
9
|
+
* transport behaviour — body decoding, the malformed-body contract, and header
|
|
10
|
+
* propagation — is unit-tested directly instead of by matching generated source.
|
|
11
|
+
*
|
|
12
|
+
* `appInjector` may be a promise: the generated module bootstraps the app at
|
|
13
|
+
* import time and passes the pending injector, which is awaited on first request
|
|
14
|
+
* and resolved instantly thereafter.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createServerFnEventHandler(appInjector: Injector | Promise<Injector>): EventHandler;
|
|
17
|
+
/**
|
|
18
|
+
* Decode a server-function request, dispatch it, and write the result to the
|
|
19
|
+
* h3 response. Same-origin, method, content-type, validation, and interceptors
|
|
20
|
+
* are enforced inside `dispatchServerFn`; this owns only the h3 I/O around it.
|
|
21
|
+
*/
|
|
22
|
+
export declare function handleServerFnRequest(event: H3Event, appInjector: Injector | Promise<Injector>): Promise<unknown>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { InjectionToken, type Provider } from '@angular/core';
|
|
2
|
+
import type { ServerFnContext } from '@analogjs/router';
|
|
3
|
+
/** Context threaded through the interceptor chain and handed to the handler. */
|
|
4
|
+
export interface ServerFnInterceptorContext {
|
|
5
|
+
readonly input: unknown;
|
|
6
|
+
readonly context: ServerFnContext;
|
|
7
|
+
/** Return a new context with additional typed fields merged in. */
|
|
8
|
+
with(patch: Partial<ServerFnContext> & Record<string, unknown>): ServerFnInterceptorContext;
|
|
9
|
+
}
|
|
10
|
+
export type ServerFnNext = (ctx: ServerFnInterceptorContext) => Promise<unknown>;
|
|
11
|
+
/** Functional interceptor, modeled on `HttpInterceptorFn`. */
|
|
12
|
+
export type ServerFnInterceptorFn = (ctx: ServerFnInterceptorContext, next: ServerFnNext) => Promise<unknown> | unknown;
|
|
13
|
+
export declare const SERVER_FN_INTERCEPTORS: InjectionToken<ServerFnInterceptorFn[]>;
|
|
14
|
+
export interface ServerFnsFeature {
|
|
15
|
+
providers: Provider[];
|
|
16
|
+
}
|
|
17
|
+
/** `withServerFnInterceptors([...])` — registers the chain (DI, ordered). */
|
|
18
|
+
export declare function withServerFnInterceptors(interceptors: ServerFnInterceptorFn[]): ServerFnsFeature;
|
|
19
|
+
/** `provideServerFns(withServerFnInterceptors(...))` — mirrors provideHttpClient. */
|
|
20
|
+
export declare function provideServerFns(...features: ServerFnsFeature[]): Provider[];
|
|
21
|
+
/**
|
|
22
|
+
* Run the interceptor chain, then the handler, threading the context.
|
|
23
|
+
*
|
|
24
|
+
* `runInCtx` re-establishes the DI injection context around each interceptor
|
|
25
|
+
* and the handler individually. This is what keeps `inject()` working in a
|
|
26
|
+
* handler even when an upstream interceptor `await`s before calling `next`
|
|
27
|
+
* (which would otherwise resume outside Angular's synchronous injection
|
|
28
|
+
* context). It defaults to a pass-through for non-DI callers/tests.
|
|
29
|
+
*/
|
|
30
|
+
export declare function runInterceptors(interceptors: ServerFnInterceptorFn[], input: unknown, handler: (input: unknown, context: ServerFnContext) => Promise<unknown> | unknown, runInCtx?: <T>(fn: () => T) => T): Promise<unknown>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import type { H3Event } from 'nitro/h3';
|
|
3
|
+
type NodeContext = NonNullable<H3Event['node']>;
|
|
4
|
+
type NodeRuntimeContext = NodeContext & {
|
|
5
|
+
req: IncomingMessage;
|
|
6
|
+
res: ServerResponse;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Dispatch provides the Node request and response through `REQUEST` and
|
|
10
|
+
* `RESPONSE`, which are typed as Node primitives, so server functions only run
|
|
11
|
+
* on a Node runtime. h3 leaves `node` undefined on other runtimes.
|
|
12
|
+
*/
|
|
13
|
+
export declare function assertNodeContext(event: Pick<H3Event, 'node'>): NodeRuntimeContext;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ServerFnDef } from '@analogjs/router';
|
|
2
|
+
/**
|
|
3
|
+
* Server-side registry of server functions, keyed by id. A `.server.ts` module
|
|
4
|
+
* populates it as a side effect of `serverFn(...)` running at import time; the
|
|
5
|
+
* Nitro dispatch route imports those modules to fill it, then looks up by id.
|
|
6
|
+
*/
|
|
7
|
+
export declare const serverFnRegistry: Map<string, ServerFnDef>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Same-origin enforcement for the server-function HTTP transport.
|
|
3
|
+
*
|
|
4
|
+
* Server functions are same-origin RPC: a client proxy only ever calls the
|
|
5
|
+
* relative `/_analog/fn/:id` URL of its own app. A cross-origin page must not be
|
|
6
|
+
* able to invoke them against a logged-in user (a CSRF-shaped attack), so the
|
|
7
|
+
* transport rejects browser requests whose origin is not the app's own — out of
|
|
8
|
+
* the box, with no per-app configuration.
|
|
9
|
+
*
|
|
10
|
+
* The signals used (`Sec-Fetch-Site`, `Origin`) are added by the browser and
|
|
11
|
+
* cannot be forged by a cross-origin page's `fetch`. Non-browser callers (curl,
|
|
12
|
+
* server-to-server, SSR in-process) send neither, so they are unaffected: the
|
|
13
|
+
* guard blocks the cross-origin browser attack it is meant to, and nothing else.
|
|
14
|
+
*/
|
|
15
|
+
import { InjectionToken } from '@angular/core';
|
|
16
|
+
import type { ServerFnsFeature } from './interceptors';
|
|
17
|
+
/** Node/h3 header bag shape (`IncomingHttpHeaders`). */
|
|
18
|
+
export type HeaderBag = Record<string, string | string[] | undefined>;
|
|
19
|
+
/**
|
|
20
|
+
* Origins permitted beyond the app's own, registered through DI:
|
|
21
|
+
* `provideServerFns(withAllowedOrigins([...]))`. Empty by default — the
|
|
22
|
+
* transport is same-origin unless an app opts out explicitly.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SERVER_FN_ALLOWED_ORIGINS: InjectionToken<string[]>;
|
|
25
|
+
/**
|
|
26
|
+
* `withAllowedOrigins([...])` — permit cross-origin browser calls from the
|
|
27
|
+
* listed origins, or pass `'*'` to disable the same-origin guard entirely.
|
|
28
|
+
* Server functions are frequently cookie-authenticated, so this is an explicit
|
|
29
|
+
* opt-out of CSRF protection: allow-list the exact origins you control.
|
|
30
|
+
*/
|
|
31
|
+
export declare function withAllowedOrigins(origins: string[]): ServerFnsFeature;
|
|
32
|
+
/**
|
|
33
|
+
* Whether an HTTP request to a server function may proceed.
|
|
34
|
+
*
|
|
35
|
+
* Allowed when the request is same-origin, carries no browser-origin signal at
|
|
36
|
+
* all (a non-browser client, or a same-origin GET that omits `Origin`), or its
|
|
37
|
+
* `Origin` is listed in `allowedOrigins`. Passing `'*'` in `allowedOrigins`
|
|
38
|
+
* disables the check — the explicit opt-in to cross-origin access.
|
|
39
|
+
*
|
|
40
|
+
* `Sec-Fetch-Site` is the authoritative signal when present: `same-origin` and
|
|
41
|
+
* `none` (a direct navigation, not a cross-site fetch) pass; `same-site` and
|
|
42
|
+
* `cross-site` require an explicit `allowedOrigins` entry. When the header is
|
|
43
|
+
* absent (older browsers, some proxies) the `Origin` host is compared to the
|
|
44
|
+
* request host as a fallback.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isServerFnOriginAllowed(headers: HeaderBag, allowedOrigins?: readonly string[]): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ServerFn, ServerFnConfig, ServerFnHandler, StandardSchemaV1 } from '@analogjs/router';
|
|
2
|
+
/**
|
|
3
|
+
* Define a server function. Authored in a `*.server.ts` module.
|
|
4
|
+
*
|
|
5
|
+
* Three call shapes, chosen for ergonomics — they all normalize to the same
|
|
6
|
+
* `(config, handler)` form and the build transform derives the route id for each:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* serverFn(() => inject(Svc).list()); // input-less GET
|
|
10
|
+
* serverFn(schema, (input) => …); // schema ⇒ POST + input
|
|
11
|
+
* serverFn({ method: 'POST' }, () => …); // explicit config
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* On the server the function self-registers and its handler runs via
|
|
15
|
+
* `dispatchServerFn`. On the client the build transform replaces the body with a
|
|
16
|
+
* proxy that calls `/_analog/fn/<id>`; the reference still carries
|
|
17
|
+
* `id`/`url`/`method` so `injectServerFn`/`ServerFnClient` can dispatch.
|
|
18
|
+
*/
|
|
19
|
+
export declare function serverFn<Out>(handler: ServerFnHandler<void, Out>): ServerFn<void, Out>;
|
|
20
|
+
export declare function serverFn<In, Out>(input: StandardSchemaV1<In>, handler: ServerFnHandler<In, Out>): ServerFn<In, Out>;
|
|
21
|
+
export declare function serverFn<In, Out>(config: ServerFnConfig<In>, handler: ServerFnHandler<In, Out>): ServerFn<In, Out>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ServerRequest, ServerResponse } from '@analogjs/router/tokens';
|
|
2
|
+
import type { ServerFnDispatcher } from '@analogjs/router';
|
|
3
|
+
/**
|
|
4
|
+
* The in-process transport used during SSR. `ServerFnClient` picks this up from
|
|
5
|
+
* DI and calls the handler directly instead of issuing an HTTP request back
|
|
6
|
+
* into the app — the render and the handler already share a process and a
|
|
7
|
+
* request, so the round-trip only adds latency (and would need an absolute URL).
|
|
8
|
+
*
|
|
9
|
+
* `method` is deliberately not passed to `dispatchServerFn`: this is a trusted
|
|
10
|
+
* in-process caller, so the HTTP-transport-only checks (same-origin, method
|
|
11
|
+
* enforcement, content type) do not apply. Validation and the interceptor chain
|
|
12
|
+
* still run, so an SSR call behaves like a browser call in every other respect.
|
|
13
|
+
*
|
|
14
|
+
* A non-2xx result is thrown as an `HttpErrorResponse` so the failure surfaces
|
|
15
|
+
* on `resource.error()` exactly as it does in the browser.
|
|
16
|
+
*/
|
|
17
|
+
export declare function createServerFnDispatcher(req: ServerRequest, res: ServerResponse): ServerFnDispatcher;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nulls `def.tView` on every component definition that Angular has
|
|
3
|
+
* compiled in this process. Angular caches the result of `consts()` on
|
|
4
|
+
* `def.tView` — that factory is where `$localize` tagged templates are
|
|
5
|
+
* evaluated — so without this reset the first rendered locale would be
|
|
6
|
+
* frozen into the cache for the process lifetime.
|
|
7
|
+
*
|
|
8
|
+
* The set on `globalThis.__ngComponentDefs` is populated by a Vite
|
|
9
|
+
* transform in `@analogjs/platform` that patches `@angular/core`'s
|
|
10
|
+
* `getComponentId()` to mirror every compiled component definition to
|
|
11
|
+
* a global Set, bypassing the `ngServerMode` guard that normally
|
|
12
|
+
* prevents registration on the server.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resetComponentDefTViews(): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure string helpers for slicing a fully rendered SSR document into the parts
|
|
3
|
+
* the streaming renderer flushes: the shell up to `<body>`, the authoritative
|
|
4
|
+
* `<body>` inner HTML for the tail, and the authoritative `<head>` inner HTML
|
|
5
|
+
* for the finalize-time head reconcile. Extracted from `render-stream` so they
|
|
6
|
+
* can be unit tested without driving the platform.
|
|
7
|
+
*/
|
|
8
|
+
/** Byte offset just after the opening `<body>` tag, or 0 if none. */
|
|
9
|
+
export declare function afterBodyOpen(html: string): number;
|
|
10
|
+
/** Inner HTML of `<body>` from a fully rendered document string. */
|
|
11
|
+
export declare function bodyInner(html: string): string;
|
|
12
|
+
/** Inner HTML of `<head>` from a fully rendered document string. */
|
|
13
|
+
export declare function headInner(html: string): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ServerContext } from '@analogjs/router/tokens';
|
|
2
|
+
/**
|
|
3
|
+
* Per-request decisions about whether the streaming renderer should fall back
|
|
4
|
+
* to a buffered render. Extracted from `render-stream` so they can be unit
|
|
5
|
+
* tested without driving the platform.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* User agents that receive a fully buffered render (with a resolved `<head>`)
|
|
9
|
+
* instead of the streamed shell. Streaming flushes the head before the app has
|
|
10
|
+
* set a dynamic title/meta and reconciles it via a finalize script; a crawler
|
|
11
|
+
* that does not run that script would index the shell's static head. Mirrors
|
|
12
|
+
* Nuxt's bot bypass — streaming targets interactive clients, bots get the
|
|
13
|
+
* buffered path whose head is byte-identical to the classic `render()`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const SSR_BOT_RE: RegExp;
|
|
16
|
+
export declare function isLikelyBot(serverContext: ServerContext): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether streaming is disabled for this request by a `streaming: false` route
|
|
19
|
+
* rule. The platform plugin translates that rule into an `x-analog-no-streaming`
|
|
20
|
+
* response header (mirroring how `ssr: false` becomes `x-analog-no-ssr`); when
|
|
21
|
+
* present, `renderStream` produces the buffered `render()` output for this
|
|
22
|
+
* route instead of streaming.
|
|
23
|
+
*/
|
|
24
|
+
export declare function streamingDisabledByRoute(serverContext: ServerContext): boolean;
|
package/types/src/index.d.ts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
export type { RouteExport } from './lib/models';
|
|
2
|
-
export type { Files } from './lib/
|
|
2
|
+
export type { Files } from './lib/route-files';
|
|
3
3
|
export { routes, createRoutes } from './lib/routes';
|
|
4
4
|
export { defineRouteMeta, injectActivatedRoute, injectRouter, } from './lib/define-route';
|
|
5
|
-
export { RouteMeta } from './lib/models';
|
|
5
|
+
export type { RouteMeta } from './lib/models';
|
|
6
6
|
export { provideFileRouter, withExtraRoutes } from './lib/provide-file-router';
|
|
7
|
-
export { MetaTag } from './lib/meta-tags';
|
|
8
|
-
export { PageServerLoad, LoadResult } from './lib/route-types';
|
|
9
|
-
export { injectLoad } from './lib/inject-load';
|
|
7
|
+
export type { MetaTag } from './lib/meta-tags';
|
|
8
|
+
export type { PageServerLoad, LoadResult, LoadDataResult, } from './lib/route-types';
|
|
9
|
+
export { injectLoad, injectLoadData } from './lib/inject-load';
|
|
10
10
|
export { getLoadResolver } from './lib/get-load-resolver';
|
|
11
11
|
export { requestContextInterceptor } from './lib/request-context';
|
|
12
12
|
export { injectRouteEndpointURL } from './lib/inject-route-endpoint-url';
|
|
13
13
|
export { FormAction } from './lib/form-action.directive';
|
|
14
|
+
export type { FormActionState } from './lib/form-action.directive';
|
|
14
15
|
export { injectDebugRoutes } from './lib/debug/routes';
|
|
15
16
|
export { withDebugRoutes } from './lib/debug';
|
|
16
|
-
export {
|
|
17
|
+
export type { AnalogJsonLdDocument } from './lib/json-ld';
|
|
18
|
+
export { issuesToFieldErrors, issuesToFormErrors, issuePathToFieldName, } from './lib/validation-errors';
|
|
19
|
+
export type { ValidationFieldErrors } from './lib/validation-errors';
|
|
20
|
+
export { injectServerFn, injectServerFnMutation, provideServerFnClient, ServerFnClient, } from './lib/server-fn/inject-server-fn';
|
|
21
|
+
export { createServerFnRef, type ServerFnRefConfig, } from './lib/server-fn/server-fn-ref';
|
|
22
|
+
export { SERVER_FN_DISPATCHER, type ServerFnDispatcher, } from './lib/server-fn/dispatcher';
|
|
23
|
+
export type { ServerFn, ServerFnConfig, ServerFnContext, ServerFnDef, ServerFnHandler, ServerFnMethod, StandardSchemaV1, } from './lib/server-fn/types';
|
|
24
|
+
export type { AnalogRouteTable, AnalogRoutePath, RoutePathOptions, RoutePathArgs, RoutePathOptionsBase, RouteParamsOutput, RouteQueryOutput, RouteLinkResult, } from './lib/route-path';
|
|
25
|
+
export { routePath } from './lib/route-path';
|
|
26
|
+
export { injectNavigate } from './lib/inject-navigate';
|
|
27
|
+
export { withTypedRouter, withRouteContext, withLoaderCaching, EXPERIMENTAL_TYPED_ROUTER, EXPERIMENTAL_ROUTE_CONTEXT, EXPERIMENTAL_LOADER_CACHE, } from './lib/experimental';
|
|
28
|
+
export type { TypedRouterOptions, LoaderCacheOptions, } from './lib/experimental';
|
|
29
|
+
export { injectParams, injectQuery } from './lib/inject-typed-params';
|
|
30
|
+
export { injectRouteContext } from './lib/inject-route-context';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { HttpRequest } from '@angular/common/http';
|
|
2
2
|
import { StateKey } from '@angular/core';
|
|
3
|
-
export declare function makeCacheKey(request: HttpRequest<
|
|
3
|
+
export declare function makeCacheKey(request: HttpRequest<unknown>, mappedRequestUrl: string): StateKey<unknown>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { HttpHandlerFn, HttpRequest, HttpEvent } from '@angular/common/http';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
|
-
import { ServerRequest } from '
|
|
3
|
+
import { type ServerRequest } from '../../tokens/src/index.js';
|
|
4
4
|
export declare function cookieInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn, location?: object, serverRequest?: ServerRequest | null): Observable<HttpEvent<unknown>>;
|
|
@@ -6,12 +6,14 @@ type CollectedRoute = {
|
|
|
6
6
|
filename: string;
|
|
7
7
|
file: string;
|
|
8
8
|
isLayout: boolean;
|
|
9
|
+
source: 'page' | 'content';
|
|
9
10
|
};
|
|
10
11
|
export default class DebugRoutesComponent implements OnInit {
|
|
11
12
|
collectedRoutes: CollectedRoute[];
|
|
12
|
-
debugRoutes
|
|
13
|
+
private debugRoutes;
|
|
14
|
+
private extraSources;
|
|
13
15
|
ngOnInit(): void;
|
|
14
|
-
traverseRoutes(routes: DebugRoute[], parent?: string): void;
|
|
16
|
+
traverseRoutes(routes: DebugRoute[], parent?: string, source?: 'page' | 'content'): void;
|
|
15
17
|
static ɵfac: i0.ɵɵFactoryDeclaration<DebugRoutesComponent, never>;
|
|
16
18
|
static ɵcmp: i0.ɵɵComponentDeclaration<DebugRoutesComponent, "analogjs-debug-routes-page", never, {}, {}, never, never, true, never>;
|
|
17
19
|
}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { Route as NgRoute, Router } from '@angular/router';
|
|
2
2
|
import { ActivatedRoute } from '@angular/router';
|
|
3
|
+
import { AnalogJsonLdDocument } from './json-ld';
|
|
4
|
+
import { MetaTag } from './meta-tags';
|
|
3
5
|
type RouteOmitted = 'component' | 'loadComponent' | 'loadChildren' | 'path' | 'pathMatch';
|
|
4
|
-
type RestrictedRoute = Omit<NgRoute, RouteOmitted
|
|
6
|
+
type RestrictedRoute = Omit<NgRoute, RouteOmitted> & {
|
|
7
|
+
meta?: MetaTag[];
|
|
8
|
+
jsonLd?: AnalogJsonLdDocument;
|
|
9
|
+
};
|
|
5
10
|
/**
|
|
6
11
|
* @deprecated Use `RouteMeta` type instead.
|
|
7
12
|
* For more info see: https://github.com/analogjs/analog/issues/223
|
|
@@ -2,4 +2,4 @@ export declare const ANALOG_META_KEY: unique symbol;
|
|
|
2
2
|
/**
|
|
3
3
|
* This variable reference is replaced with a glob of all route endpoints.
|
|
4
4
|
*/
|
|
5
|
-
export declare const ANALOG_PAGE_ENDPOINTS:
|
|
5
|
+
export declare const ANALOG_PAGE_ENDPOINTS: Record<string, () => Promise<unknown>>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
import type { RouterFeatures } from '@angular/router';
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for experimental typed router features.
|
|
5
|
+
*
|
|
6
|
+
* Inspired by TanStack Router's type-safe navigation system where
|
|
7
|
+
* routes are registered globally and all navigation/hooks are typed
|
|
8
|
+
* against the route tree.
|
|
9
|
+
*
|
|
10
|
+
* @experimental
|
|
11
|
+
*/
|
|
12
|
+
export interface TypedRouterOptions {
|
|
13
|
+
/**
|
|
14
|
+
* When true, logs warnings in development when navigating to
|
|
15
|
+
* routes with params that don't match the generated route table.
|
|
16
|
+
*
|
|
17
|
+
* Similar to TanStack Router's strict mode where `useParams()`
|
|
18
|
+
* without a `from` constraint returns a union of all possible params.
|
|
19
|
+
*
|
|
20
|
+
* @default false
|
|
21
|
+
*/
|
|
22
|
+
strictRouteParams?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Configuration for experimental loader caching.
|
|
26
|
+
*
|
|
27
|
+
* Inspired by TanStack Router's built-in data caching where route
|
|
28
|
+
* loaders automatically cache results and support stale-while-revalidate.
|
|
29
|
+
*
|
|
30
|
+
* @experimental
|
|
31
|
+
*/
|
|
32
|
+
export interface LoaderCacheOptions {
|
|
33
|
+
/**
|
|
34
|
+
* Time in milliseconds before loader data is considered stale.
|
|
35
|
+
* While data is fresh, navigating back to the route uses cached
|
|
36
|
+
* data without re-invoking the server load function.
|
|
37
|
+
*
|
|
38
|
+
* Mirrors TanStack Router's `defaultStaleTime` option on `createRouter()`.
|
|
39
|
+
*
|
|
40
|
+
* @default 0 (always re-fetch)
|
|
41
|
+
*/
|
|
42
|
+
defaultStaleTime?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Time in milliseconds to retain unused loader data in cache
|
|
45
|
+
* after leaving a route. After this period the cached entry is
|
|
46
|
+
* garbage-collected.
|
|
47
|
+
*
|
|
48
|
+
* Mirrors TanStack Router's `defaultGcTime` (default 30 min).
|
|
49
|
+
*
|
|
50
|
+
* @default 300_000 (5 minutes)
|
|
51
|
+
*/
|
|
52
|
+
defaultGcTime?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Delay in milliseconds before showing a pending/loading indicator
|
|
55
|
+
* during route transitions. Prevents flash-of-loading-state for
|
|
56
|
+
* fast navigations.
|
|
57
|
+
*
|
|
58
|
+
* Mirrors TanStack Router's `defaultPendingMs`.
|
|
59
|
+
*
|
|
60
|
+
* @default 0 (show immediately)
|
|
61
|
+
*/
|
|
62
|
+
defaultPendingMs?: number;
|
|
63
|
+
}
|
|
64
|
+
/** @experimental */
|
|
65
|
+
export declare const EXPERIMENTAL_TYPED_ROUTER: InjectionToken<TypedRouterOptions>;
|
|
66
|
+
/** @experimental */
|
|
67
|
+
export declare const EXPERIMENTAL_ROUTE_CONTEXT: InjectionToken<Record<string, unknown>>;
|
|
68
|
+
/** @experimental */
|
|
69
|
+
export declare const EXPERIMENTAL_LOADER_CACHE: InjectionToken<LoaderCacheOptions>;
|
|
70
|
+
/**
|
|
71
|
+
* Enables experimental typed router features.
|
|
72
|
+
*
|
|
73
|
+
* When active, `routePath()`, `injectNavigate()`, `injectParams()`,
|
|
74
|
+
* and `injectQuery()` will enforce route table constraints and
|
|
75
|
+
* optionally log warnings in strict mode.
|
|
76
|
+
*
|
|
77
|
+
* Inspired by TanStack Router's `Register` interface and strict type
|
|
78
|
+
* checking across the entire navigation surface.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* provideFileRouter(
|
|
83
|
+
* withTypedRouter({ strictRouteParams: true }),
|
|
84
|
+
* )
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @experimental
|
|
88
|
+
*/
|
|
89
|
+
export declare function withTypedRouter(options?: TypedRouterOptions): RouterFeatures;
|
|
90
|
+
/**
|
|
91
|
+
* Provides root-level route context available to all route loaders
|
|
92
|
+
* and components via `injectRouteContext()`.
|
|
93
|
+
*
|
|
94
|
+
* Inspired by TanStack Router's `createRootRouteWithContext<T>()` where
|
|
95
|
+
* a typed context object is required at router creation and automatically
|
|
96
|
+
* available in every route's `beforeLoad` and `loader`.
|
|
97
|
+
*
|
|
98
|
+
* In Angular terms, this creates a DI token that server-side load
|
|
99
|
+
* functions and components can inject to access shared services
|
|
100
|
+
* without importing them individually.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* // app.config.ts
|
|
105
|
+
* provideFileRouter(
|
|
106
|
+
* withRouteContext({
|
|
107
|
+
* auth: inject(AuthService),
|
|
108
|
+
* db: inject(DatabaseService),
|
|
109
|
+
* }),
|
|
110
|
+
* )
|
|
111
|
+
*
|
|
112
|
+
* // In a component
|
|
113
|
+
* const ctx = injectRouteContext<{ auth: AuthService; db: DatabaseService }>();
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @experimental
|
|
117
|
+
*/
|
|
118
|
+
export declare function withRouteContext<T extends Record<string, unknown>>(context: T): RouterFeatures;
|
|
119
|
+
/**
|
|
120
|
+
* Configures experimental loader caching behavior for server-loaded
|
|
121
|
+
* route data.
|
|
122
|
+
*
|
|
123
|
+
* Inspired by TanStack Router's built-in cache where `createRouter()`
|
|
124
|
+
* accepts `defaultStaleTime` and `defaultGcTime` to control when
|
|
125
|
+
* loaders re-execute and when cached data is discarded.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* provideFileRouter(
|
|
130
|
+
* withLoaderCaching({
|
|
131
|
+
* defaultStaleTime: 30_000, // 30s before re-fetch
|
|
132
|
+
* defaultGcTime: 300_000, // 5min cache retention
|
|
133
|
+
* defaultPendingMs: 200, // 200ms loading delay
|
|
134
|
+
* }),
|
|
135
|
+
* )
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @experimental
|
|
139
|
+
*/
|
|
140
|
+
export declare function withLoaderCaching(options?: LoaderCacheOptions): RouterFeatures;
|