@finesoft/front 0.1.38 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/app-XEMPAI6H.js +10 -0
- package/dist/browser.cjs +219 -19
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +148 -15
- package/dist/browser.d.ts +148 -15
- package/dist/browser.js +18 -2
- package/dist/{chunk-PHDR7PIL.js → chunk-4PPCVAKZ.js} +98 -17
- package/dist/chunk-4PPCVAKZ.js.map +1 -0
- package/dist/{chunk-SFGR32K6.js → chunk-OYTIGVEG.js} +13 -8
- package/dist/chunk-OYTIGVEG.js.map +1 -0
- package/dist/{chunk-OXKFPW4U.js → chunk-SDPWQT2T.js} +118 -6
- package/dist/chunk-SDPWQT2T.js.map +1 -0
- package/dist/{chunk-AYO3UUQC.js → chunk-XQ3UWZOS.js} +72 -3
- package/dist/chunk-XQ3UWZOS.js.map +1 -0
- package/dist/index.cjs +319 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +24 -8
- package/dist/index.js.map +1 -1
- package/dist/{src-MVACJWBF.js → src-XNC7QNVI.js} +3 -3
- package/package.json +1 -1
- package/dist/app-D4K35MX3.js +0 -10
- package/dist/chunk-AYO3UUQC.js.map +0 -1
- package/dist/chunk-OXKFPW4U.js.map +0 -1
- package/dist/chunk-PHDR7PIL.js.map +0 -1
- package/dist/chunk-SFGR32K6.js.map +0 -1
- /package/dist/{app-D4K35MX3.js.map → app-XEMPAI6H.js.map} +0 -0
- /package/dist/{src-MVACJWBF.js.map → src-XNC7QNVI.js.map} +0 -0
package/dist/browser.d.cts
CHANGED
|
@@ -173,6 +173,88 @@ interface MakeDependenciesOptions {
|
|
|
173
173
|
}
|
|
174
174
|
declare function makeDependencies(container: Container, options?: MakeDependenciesOptions): void;
|
|
175
175
|
|
|
176
|
+
/**
|
|
177
|
+
* BasePage — 所有页面共享的基础属性
|
|
178
|
+
*
|
|
179
|
+
* 具体页面类型由应用层定义并扩展此接口。
|
|
180
|
+
*/
|
|
181
|
+
interface BasePage {
|
|
182
|
+
id: string;
|
|
183
|
+
pageType: string;
|
|
184
|
+
title: string;
|
|
185
|
+
description?: string;
|
|
186
|
+
url?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Navigation Middleware — 类型定义
|
|
191
|
+
*
|
|
192
|
+
* 两阶段导航中间件管线:
|
|
193
|
+
* 1. beforeLoad — 路由匹配后、数据加载前(认证守卫、权限检查、早期重定向)
|
|
194
|
+
* 2. afterLoad — 数据加载后、渲染前(URL 规范化、基于数据的守卫)
|
|
195
|
+
*
|
|
196
|
+
* SSR 和 CSR 共享同一套中间件定义。
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
/** 导航上下文(beforeLoad 阶段可用) */
|
|
200
|
+
interface NavigationContext {
|
|
201
|
+
/** 完整 URL(path + query) */
|
|
202
|
+
readonly url: string;
|
|
203
|
+
/** 仅路径部分 */
|
|
204
|
+
readonly path: string;
|
|
205
|
+
/** 路由参数 + 查询参数 */
|
|
206
|
+
readonly params: Record<string, string>;
|
|
207
|
+
/** 匹配的 Intent */
|
|
208
|
+
readonly intent: Intent;
|
|
209
|
+
/** 是否在服务端运行 */
|
|
210
|
+
readonly isServer: boolean;
|
|
211
|
+
/** DI 容器(可获取自定义服务) */
|
|
212
|
+
readonly container: Container;
|
|
213
|
+
/** 获取 Cookie 值(两端均可用) */
|
|
214
|
+
getCookie(name: string): string | undefined;
|
|
215
|
+
/** 获取请求头值(仅服务端有值,客户端始终返回 undefined) */
|
|
216
|
+
getHeader(name: string): string | undefined;
|
|
217
|
+
}
|
|
218
|
+
/** 后置上下文(afterLoad 阶段,包含页面数据) */
|
|
219
|
+
interface PostLoadContext extends NavigationContext {
|
|
220
|
+
/** 控制器返回的页面数据 */
|
|
221
|
+
readonly page: BasePage;
|
|
222
|
+
}
|
|
223
|
+
/** 继续执行下一个中间件 */
|
|
224
|
+
interface NextResult {
|
|
225
|
+
readonly kind: "next";
|
|
226
|
+
}
|
|
227
|
+
/** 重定向(服务端: HTTP 301/302,客户端: 触发新导航) */
|
|
228
|
+
interface RedirectResult {
|
|
229
|
+
readonly kind: "redirect";
|
|
230
|
+
readonly url: string;
|
|
231
|
+
readonly status: number;
|
|
232
|
+
}
|
|
233
|
+
/** URL 重写(服务端: HTTP 301,客户端: replaceState 仅更新地址栏) */
|
|
234
|
+
interface RewriteResult {
|
|
235
|
+
readonly kind: "rewrite";
|
|
236
|
+
readonly url: string;
|
|
237
|
+
}
|
|
238
|
+
/** 拒绝访问 */
|
|
239
|
+
interface DenyResult {
|
|
240
|
+
readonly kind: "deny";
|
|
241
|
+
readonly status: number;
|
|
242
|
+
readonly message: string;
|
|
243
|
+
}
|
|
244
|
+
type MiddlewareResult = NextResult | RedirectResult | RewriteResult | DenyResult;
|
|
245
|
+
/** 继续执行 */
|
|
246
|
+
declare function next(): NextResult;
|
|
247
|
+
/** 重定向到新 URL */
|
|
248
|
+
declare function redirect(url: string, status?: 301 | 302): RedirectResult;
|
|
249
|
+
/** URL 重写(不重新加载数据) */
|
|
250
|
+
declare function rewrite(url: string): RewriteResult;
|
|
251
|
+
/** 拒绝访问 */
|
|
252
|
+
declare function deny(status?: number, message?: string): DenyResult;
|
|
253
|
+
/** beforeLoad 守卫:路由匹配后、数据加载前 */
|
|
254
|
+
type BeforeLoadGuard = (ctx: NavigationContext) => MiddlewareResult | Promise<MiddlewareResult>;
|
|
255
|
+
/** afterLoad 守卫:数据加载后、渲染前 */
|
|
256
|
+
type AfterLoadGuard = (ctx: PostLoadContext) => MiddlewareResult | Promise<MiddlewareResult>;
|
|
257
|
+
|
|
176
258
|
/**
|
|
177
259
|
* URL 路由器 — URL pattern → Intent + FlowAction
|
|
178
260
|
*/
|
|
@@ -182,11 +264,21 @@ interface RouteMatch {
|
|
|
182
264
|
intent: Intent;
|
|
183
265
|
action: FlowAction;
|
|
184
266
|
renderMode?: string;
|
|
267
|
+
/** 该路由绑定的 beforeLoad 守卫 */
|
|
268
|
+
beforeGuards?: BeforeLoadGuard[];
|
|
269
|
+
/** 该路由绑定的 afterLoad 守卫 */
|
|
270
|
+
afterGuards?: AfterLoadGuard[];
|
|
271
|
+
}
|
|
272
|
+
/** 路由添加选项 */
|
|
273
|
+
interface RouteAddOptions {
|
|
274
|
+
renderMode?: string;
|
|
275
|
+
beforeGuards?: BeforeLoadGuard[];
|
|
276
|
+
afterGuards?: AfterLoadGuard[];
|
|
185
277
|
}
|
|
186
278
|
declare class Router {
|
|
187
279
|
private routes;
|
|
188
280
|
/** 添加路由规则 */
|
|
189
|
-
add(pattern: string, intentId: string,
|
|
281
|
+
add(pattern: string, intentId: string, renderModeOrOptions?: string | RouteAddOptions): this;
|
|
190
282
|
/** 解析 URL → RouteMatch */
|
|
191
283
|
resolve(urlOrPath: string): RouteMatch | null;
|
|
192
284
|
/** 获取所有已注册的路由 */
|
|
@@ -253,19 +345,6 @@ declare class ConsoleLoggerFactory implements LoggerFactory {
|
|
|
253
345
|
declare function shouldLog(name: string, level: Level): boolean;
|
|
254
346
|
declare function resetFilterCache(): void;
|
|
255
347
|
|
|
256
|
-
/**
|
|
257
|
-
* BasePage — 所有页面共享的基础属性
|
|
258
|
-
*
|
|
259
|
-
* 具体页面类型由应用层定义并扩展此接口。
|
|
260
|
-
*/
|
|
261
|
-
interface BasePage {
|
|
262
|
-
id: string;
|
|
263
|
-
pageType: string;
|
|
264
|
-
title: string;
|
|
265
|
-
description?: string;
|
|
266
|
-
url?: string;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
348
|
/**
|
|
270
349
|
* PrefetchedIntents — SSR 数据缓存
|
|
271
350
|
*
|
|
@@ -315,6 +394,8 @@ declare class Framework {
|
|
|
315
394
|
readonly actionDispatcher: ActionDispatcher;
|
|
316
395
|
readonly router: Router;
|
|
317
396
|
readonly prefetchedIntents: PrefetchedIntents;
|
|
397
|
+
private readonly beforeGuards;
|
|
398
|
+
private readonly afterGuards;
|
|
318
399
|
private constructor();
|
|
319
400
|
/** 创建并初始化 Framework 实例 */
|
|
320
401
|
static create(config?: FrameworkConfig): Framework;
|
|
@@ -330,6 +411,14 @@ declare class Framework {
|
|
|
330
411
|
onAction<A extends Action>(kind: string, handler: ActionHandler<A>): void;
|
|
331
412
|
/** 注册 Intent Controller */
|
|
332
413
|
registerIntent(controller: IntentController): void;
|
|
414
|
+
/** 注册 beforeLoad 守卫(路由匹配后、数据加载前) */
|
|
415
|
+
beforeLoad(guard: BeforeLoadGuard): void;
|
|
416
|
+
/** 注册 afterLoad 守卫(数据加载后、渲染前) */
|
|
417
|
+
afterLoad(guard: AfterLoadGuard): void;
|
|
418
|
+
/** 执行所有 beforeLoad 守卫(全局 → 路由级) */
|
|
419
|
+
runBeforeLoad(ctx: NavigationContext, routeGuards?: BeforeLoadGuard[]): Promise<MiddlewareResult>;
|
|
420
|
+
/** 执行所有 afterLoad 守卫(全局 → 路由级) */
|
|
421
|
+
runAfterLoad(ctx: PostLoadContext, routeGuards?: AfterLoadGuard[]): Promise<MiddlewareResult>;
|
|
333
422
|
/** 销毁 Framework 实例 */
|
|
334
423
|
dispose(): void;
|
|
335
424
|
}
|
|
@@ -555,6 +644,16 @@ interface RouteDefinition {
|
|
|
555
644
|
* - "prerender": 预渲染(构建时生成静态 HTML + ISR 缓存)
|
|
556
645
|
*/
|
|
557
646
|
renderMode?: RenderMode;
|
|
647
|
+
/**
|
|
648
|
+
* 路由级 beforeLoad 守卫(可选)。
|
|
649
|
+
* 在全局守卫之后执行,仅对匹配此路由的请求生效。
|
|
650
|
+
*/
|
|
651
|
+
beforeLoad?: BeforeLoadGuard[];
|
|
652
|
+
/**
|
|
653
|
+
* 路由级 afterLoad 守卫(可选)。
|
|
654
|
+
* 在全局守卫之后执行,仅对匹配此路由的请求生效。
|
|
655
|
+
*/
|
|
656
|
+
afterLoad?: AfterLoadGuard[];
|
|
558
657
|
}
|
|
559
658
|
/**
|
|
560
659
|
* 声明式注册路由和 Controller
|
|
@@ -617,6 +716,40 @@ declare function buildUrl(path: string, params?: Record<string, string | undefin
|
|
|
617
716
|
*/
|
|
618
717
|
declare function generateUuid(): string;
|
|
619
718
|
|
|
719
|
+
/**
|
|
720
|
+
* Navigation Context — 构建器
|
|
721
|
+
*
|
|
722
|
+
* 为 SSR(服务端)和 Browser(客户端)两种环境创建统一的 NavigationContext。
|
|
723
|
+
*/
|
|
724
|
+
|
|
725
|
+
interface ServerContextOptions {
|
|
726
|
+
url: string;
|
|
727
|
+
intent: Intent;
|
|
728
|
+
container: Container;
|
|
729
|
+
/** 原始 Request 对象(提取 cookie 和 header) */
|
|
730
|
+
request?: Request;
|
|
731
|
+
}
|
|
732
|
+
/** 从 Request 对象构建服务端上下文 */
|
|
733
|
+
declare function createServerContext(options: ServerContextOptions): NavigationContext;
|
|
734
|
+
interface BrowserContextOptions {
|
|
735
|
+
url: string;
|
|
736
|
+
intent: Intent;
|
|
737
|
+
container: Container;
|
|
738
|
+
}
|
|
739
|
+
/** 从 document.cookie 构建浏览器端上下文 */
|
|
740
|
+
declare function createBrowserContext(options: BrowserContextOptions): NavigationContext;
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Guard Pipeline — 顺序执行守卫链
|
|
744
|
+
*
|
|
745
|
+
* 按注册顺序执行守卫,遇到第一个非 `next` 结果立即短路返回。
|
|
746
|
+
*/
|
|
747
|
+
|
|
748
|
+
/** 执行 beforeLoad 守卫链 */
|
|
749
|
+
declare function runBeforeLoadGuards(guards: BeforeLoadGuard[], ctx: NavigationContext): Promise<MiddlewareResult>;
|
|
750
|
+
/** 执行 afterLoad 守卫链 */
|
|
751
|
+
declare function runAfterLoadGuards(guards: AfterLoadGuard[], ctx: PostLoadContext): Promise<MiddlewareResult>;
|
|
752
|
+
|
|
620
753
|
/**
|
|
621
754
|
* ExternalUrl Action Handler — 外部链接处理器
|
|
622
755
|
*/
|
|
@@ -768,4 +901,4 @@ declare function deserializeServerData(): PrefetchedIntent[] | undefined;
|
|
|
768
901
|
*/
|
|
769
902
|
declare function createPrefetchedIntentsFromDom(): PrefetchedIntents;
|
|
770
903
|
|
|
771
|
-
export { ACTION_KINDS, type Action, ActionDispatcher, type ActionHandler, type ActionHandlerDependencies, type AsyncMapper, BaseController, type BaseItem, BaseLogger, type BasePage, type BaseShelf, type BrowserAppConfig, CompositeLogger, CompositeLoggerFactory, type CompoundAction, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, type ExternalUrlAction, type ExternalUrlDependencies, type FeatureFlags, type FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, type FrameworkConfig, History, HttpClient, type HttpClientConfig, HttpError, type Intent, type IntentController, IntentDispatcher, type Locale, type Logger, type LoggerFactory, type Logger as LoggerInterface, LruMap, type Mapper, type MetricsRecorder, type Net, type None, type Optional, type PrefetchedIntent, PrefetchedIntents, type RenderMode, type RouteDefinition, type RouteMatch, Router, type Storage, buildUrl, createPrefetchedIntentsFromDom, defineRoutes, deserializeServerData, generateUuid, getBaseUrl, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, mapEach, pipe, pipeAsync, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, removeHost, removeQueryParams, removeScheme, resetFilterCache, shouldLog, stableStringify, startBrowserApp, tryScroll };
|
|
904
|
+
export { ACTION_KINDS, type Action, ActionDispatcher, type ActionHandler, type ActionHandlerDependencies, type AfterLoadGuard, type AsyncMapper, BaseController, type BaseItem, BaseLogger, type BasePage, type BaseShelf, type BeforeLoadGuard, type BrowserAppConfig, type BrowserContextOptions, CompositeLogger, CompositeLoggerFactory, type CompoundAction, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, type DenyResult, type ExternalUrlAction, type ExternalUrlDependencies, type FeatureFlags, type FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, type FrameworkConfig, History, HttpClient, type HttpClientConfig, HttpError, type Intent, type IntentController, IntentDispatcher, type Locale, type Logger, type LoggerFactory, type Logger as LoggerInterface, LruMap, type Mapper, type MetricsRecorder, type MiddlewareResult, type NavigationContext, type Net, type NextResult, type None, type Optional, type PostLoadContext, type PrefetchedIntent, PrefetchedIntents, type RedirectResult, type RenderMode, type RewriteResult, type RouteAddOptions, type RouteDefinition, type RouteMatch, Router, type ServerContextOptions, type Storage, buildUrl, createBrowserContext, createPrefetchedIntentsFromDom, createServerContext, defineRoutes, deny, deserializeServerData, generateUuid, getBaseUrl, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, mapEach, next, pipe, pipeAsync, redirect, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, removeHost, removeQueryParams, removeScheme, resetFilterCache, rewrite, runAfterLoadGuards, runBeforeLoadGuards, shouldLog, stableStringify, startBrowserApp, tryScroll };
|
package/dist/browser.d.ts
CHANGED
|
@@ -173,6 +173,88 @@ interface MakeDependenciesOptions {
|
|
|
173
173
|
}
|
|
174
174
|
declare function makeDependencies(container: Container, options?: MakeDependenciesOptions): void;
|
|
175
175
|
|
|
176
|
+
/**
|
|
177
|
+
* BasePage — 所有页面共享的基础属性
|
|
178
|
+
*
|
|
179
|
+
* 具体页面类型由应用层定义并扩展此接口。
|
|
180
|
+
*/
|
|
181
|
+
interface BasePage {
|
|
182
|
+
id: string;
|
|
183
|
+
pageType: string;
|
|
184
|
+
title: string;
|
|
185
|
+
description?: string;
|
|
186
|
+
url?: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Navigation Middleware — 类型定义
|
|
191
|
+
*
|
|
192
|
+
* 两阶段导航中间件管线:
|
|
193
|
+
* 1. beforeLoad — 路由匹配后、数据加载前(认证守卫、权限检查、早期重定向)
|
|
194
|
+
* 2. afterLoad — 数据加载后、渲染前(URL 规范化、基于数据的守卫)
|
|
195
|
+
*
|
|
196
|
+
* SSR 和 CSR 共享同一套中间件定义。
|
|
197
|
+
*/
|
|
198
|
+
|
|
199
|
+
/** 导航上下文(beforeLoad 阶段可用) */
|
|
200
|
+
interface NavigationContext {
|
|
201
|
+
/** 完整 URL(path + query) */
|
|
202
|
+
readonly url: string;
|
|
203
|
+
/** 仅路径部分 */
|
|
204
|
+
readonly path: string;
|
|
205
|
+
/** 路由参数 + 查询参数 */
|
|
206
|
+
readonly params: Record<string, string>;
|
|
207
|
+
/** 匹配的 Intent */
|
|
208
|
+
readonly intent: Intent;
|
|
209
|
+
/** 是否在服务端运行 */
|
|
210
|
+
readonly isServer: boolean;
|
|
211
|
+
/** DI 容器(可获取自定义服务) */
|
|
212
|
+
readonly container: Container;
|
|
213
|
+
/** 获取 Cookie 值(两端均可用) */
|
|
214
|
+
getCookie(name: string): string | undefined;
|
|
215
|
+
/** 获取请求头值(仅服务端有值,客户端始终返回 undefined) */
|
|
216
|
+
getHeader(name: string): string | undefined;
|
|
217
|
+
}
|
|
218
|
+
/** 后置上下文(afterLoad 阶段,包含页面数据) */
|
|
219
|
+
interface PostLoadContext extends NavigationContext {
|
|
220
|
+
/** 控制器返回的页面数据 */
|
|
221
|
+
readonly page: BasePage;
|
|
222
|
+
}
|
|
223
|
+
/** 继续执行下一个中间件 */
|
|
224
|
+
interface NextResult {
|
|
225
|
+
readonly kind: "next";
|
|
226
|
+
}
|
|
227
|
+
/** 重定向(服务端: HTTP 301/302,客户端: 触发新导航) */
|
|
228
|
+
interface RedirectResult {
|
|
229
|
+
readonly kind: "redirect";
|
|
230
|
+
readonly url: string;
|
|
231
|
+
readonly status: number;
|
|
232
|
+
}
|
|
233
|
+
/** URL 重写(服务端: HTTP 301,客户端: replaceState 仅更新地址栏) */
|
|
234
|
+
interface RewriteResult {
|
|
235
|
+
readonly kind: "rewrite";
|
|
236
|
+
readonly url: string;
|
|
237
|
+
}
|
|
238
|
+
/** 拒绝访问 */
|
|
239
|
+
interface DenyResult {
|
|
240
|
+
readonly kind: "deny";
|
|
241
|
+
readonly status: number;
|
|
242
|
+
readonly message: string;
|
|
243
|
+
}
|
|
244
|
+
type MiddlewareResult = NextResult | RedirectResult | RewriteResult | DenyResult;
|
|
245
|
+
/** 继续执行 */
|
|
246
|
+
declare function next(): NextResult;
|
|
247
|
+
/** 重定向到新 URL */
|
|
248
|
+
declare function redirect(url: string, status?: 301 | 302): RedirectResult;
|
|
249
|
+
/** URL 重写(不重新加载数据) */
|
|
250
|
+
declare function rewrite(url: string): RewriteResult;
|
|
251
|
+
/** 拒绝访问 */
|
|
252
|
+
declare function deny(status?: number, message?: string): DenyResult;
|
|
253
|
+
/** beforeLoad 守卫:路由匹配后、数据加载前 */
|
|
254
|
+
type BeforeLoadGuard = (ctx: NavigationContext) => MiddlewareResult | Promise<MiddlewareResult>;
|
|
255
|
+
/** afterLoad 守卫:数据加载后、渲染前 */
|
|
256
|
+
type AfterLoadGuard = (ctx: PostLoadContext) => MiddlewareResult | Promise<MiddlewareResult>;
|
|
257
|
+
|
|
176
258
|
/**
|
|
177
259
|
* URL 路由器 — URL pattern → Intent + FlowAction
|
|
178
260
|
*/
|
|
@@ -182,11 +264,21 @@ interface RouteMatch {
|
|
|
182
264
|
intent: Intent;
|
|
183
265
|
action: FlowAction;
|
|
184
266
|
renderMode?: string;
|
|
267
|
+
/** 该路由绑定的 beforeLoad 守卫 */
|
|
268
|
+
beforeGuards?: BeforeLoadGuard[];
|
|
269
|
+
/** 该路由绑定的 afterLoad 守卫 */
|
|
270
|
+
afterGuards?: AfterLoadGuard[];
|
|
271
|
+
}
|
|
272
|
+
/** 路由添加选项 */
|
|
273
|
+
interface RouteAddOptions {
|
|
274
|
+
renderMode?: string;
|
|
275
|
+
beforeGuards?: BeforeLoadGuard[];
|
|
276
|
+
afterGuards?: AfterLoadGuard[];
|
|
185
277
|
}
|
|
186
278
|
declare class Router {
|
|
187
279
|
private routes;
|
|
188
280
|
/** 添加路由规则 */
|
|
189
|
-
add(pattern: string, intentId: string,
|
|
281
|
+
add(pattern: string, intentId: string, renderModeOrOptions?: string | RouteAddOptions): this;
|
|
190
282
|
/** 解析 URL → RouteMatch */
|
|
191
283
|
resolve(urlOrPath: string): RouteMatch | null;
|
|
192
284
|
/** 获取所有已注册的路由 */
|
|
@@ -253,19 +345,6 @@ declare class ConsoleLoggerFactory implements LoggerFactory {
|
|
|
253
345
|
declare function shouldLog(name: string, level: Level): boolean;
|
|
254
346
|
declare function resetFilterCache(): void;
|
|
255
347
|
|
|
256
|
-
/**
|
|
257
|
-
* BasePage — 所有页面共享的基础属性
|
|
258
|
-
*
|
|
259
|
-
* 具体页面类型由应用层定义并扩展此接口。
|
|
260
|
-
*/
|
|
261
|
-
interface BasePage {
|
|
262
|
-
id: string;
|
|
263
|
-
pageType: string;
|
|
264
|
-
title: string;
|
|
265
|
-
description?: string;
|
|
266
|
-
url?: string;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
348
|
/**
|
|
270
349
|
* PrefetchedIntents — SSR 数据缓存
|
|
271
350
|
*
|
|
@@ -315,6 +394,8 @@ declare class Framework {
|
|
|
315
394
|
readonly actionDispatcher: ActionDispatcher;
|
|
316
395
|
readonly router: Router;
|
|
317
396
|
readonly prefetchedIntents: PrefetchedIntents;
|
|
397
|
+
private readonly beforeGuards;
|
|
398
|
+
private readonly afterGuards;
|
|
318
399
|
private constructor();
|
|
319
400
|
/** 创建并初始化 Framework 实例 */
|
|
320
401
|
static create(config?: FrameworkConfig): Framework;
|
|
@@ -330,6 +411,14 @@ declare class Framework {
|
|
|
330
411
|
onAction<A extends Action>(kind: string, handler: ActionHandler<A>): void;
|
|
331
412
|
/** 注册 Intent Controller */
|
|
332
413
|
registerIntent(controller: IntentController): void;
|
|
414
|
+
/** 注册 beforeLoad 守卫(路由匹配后、数据加载前) */
|
|
415
|
+
beforeLoad(guard: BeforeLoadGuard): void;
|
|
416
|
+
/** 注册 afterLoad 守卫(数据加载后、渲染前) */
|
|
417
|
+
afterLoad(guard: AfterLoadGuard): void;
|
|
418
|
+
/** 执行所有 beforeLoad 守卫(全局 → 路由级) */
|
|
419
|
+
runBeforeLoad(ctx: NavigationContext, routeGuards?: BeforeLoadGuard[]): Promise<MiddlewareResult>;
|
|
420
|
+
/** 执行所有 afterLoad 守卫(全局 → 路由级) */
|
|
421
|
+
runAfterLoad(ctx: PostLoadContext, routeGuards?: AfterLoadGuard[]): Promise<MiddlewareResult>;
|
|
333
422
|
/** 销毁 Framework 实例 */
|
|
334
423
|
dispose(): void;
|
|
335
424
|
}
|
|
@@ -555,6 +644,16 @@ interface RouteDefinition {
|
|
|
555
644
|
* - "prerender": 预渲染(构建时生成静态 HTML + ISR 缓存)
|
|
556
645
|
*/
|
|
557
646
|
renderMode?: RenderMode;
|
|
647
|
+
/**
|
|
648
|
+
* 路由级 beforeLoad 守卫(可选)。
|
|
649
|
+
* 在全局守卫之后执行,仅对匹配此路由的请求生效。
|
|
650
|
+
*/
|
|
651
|
+
beforeLoad?: BeforeLoadGuard[];
|
|
652
|
+
/**
|
|
653
|
+
* 路由级 afterLoad 守卫(可选)。
|
|
654
|
+
* 在全局守卫之后执行,仅对匹配此路由的请求生效。
|
|
655
|
+
*/
|
|
656
|
+
afterLoad?: AfterLoadGuard[];
|
|
558
657
|
}
|
|
559
658
|
/**
|
|
560
659
|
* 声明式注册路由和 Controller
|
|
@@ -617,6 +716,40 @@ declare function buildUrl(path: string, params?: Record<string, string | undefin
|
|
|
617
716
|
*/
|
|
618
717
|
declare function generateUuid(): string;
|
|
619
718
|
|
|
719
|
+
/**
|
|
720
|
+
* Navigation Context — 构建器
|
|
721
|
+
*
|
|
722
|
+
* 为 SSR(服务端)和 Browser(客户端)两种环境创建统一的 NavigationContext。
|
|
723
|
+
*/
|
|
724
|
+
|
|
725
|
+
interface ServerContextOptions {
|
|
726
|
+
url: string;
|
|
727
|
+
intent: Intent;
|
|
728
|
+
container: Container;
|
|
729
|
+
/** 原始 Request 对象(提取 cookie 和 header) */
|
|
730
|
+
request?: Request;
|
|
731
|
+
}
|
|
732
|
+
/** 从 Request 对象构建服务端上下文 */
|
|
733
|
+
declare function createServerContext(options: ServerContextOptions): NavigationContext;
|
|
734
|
+
interface BrowserContextOptions {
|
|
735
|
+
url: string;
|
|
736
|
+
intent: Intent;
|
|
737
|
+
container: Container;
|
|
738
|
+
}
|
|
739
|
+
/** 从 document.cookie 构建浏览器端上下文 */
|
|
740
|
+
declare function createBrowserContext(options: BrowserContextOptions): NavigationContext;
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Guard Pipeline — 顺序执行守卫链
|
|
744
|
+
*
|
|
745
|
+
* 按注册顺序执行守卫,遇到第一个非 `next` 结果立即短路返回。
|
|
746
|
+
*/
|
|
747
|
+
|
|
748
|
+
/** 执行 beforeLoad 守卫链 */
|
|
749
|
+
declare function runBeforeLoadGuards(guards: BeforeLoadGuard[], ctx: NavigationContext): Promise<MiddlewareResult>;
|
|
750
|
+
/** 执行 afterLoad 守卫链 */
|
|
751
|
+
declare function runAfterLoadGuards(guards: AfterLoadGuard[], ctx: PostLoadContext): Promise<MiddlewareResult>;
|
|
752
|
+
|
|
620
753
|
/**
|
|
621
754
|
* ExternalUrl Action Handler — 外部链接处理器
|
|
622
755
|
*/
|
|
@@ -768,4 +901,4 @@ declare function deserializeServerData(): PrefetchedIntent[] | undefined;
|
|
|
768
901
|
*/
|
|
769
902
|
declare function createPrefetchedIntentsFromDom(): PrefetchedIntents;
|
|
770
903
|
|
|
771
|
-
export { ACTION_KINDS, type Action, ActionDispatcher, type ActionHandler, type ActionHandlerDependencies, type AsyncMapper, BaseController, type BaseItem, BaseLogger, type BasePage, type BaseShelf, type BrowserAppConfig, CompositeLogger, CompositeLoggerFactory, type CompoundAction, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, type ExternalUrlAction, type ExternalUrlDependencies, type FeatureFlags, type FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, type FrameworkConfig, History, HttpClient, type HttpClientConfig, HttpError, type Intent, type IntentController, IntentDispatcher, type Locale, type Logger, type LoggerFactory, type Logger as LoggerInterface, LruMap, type Mapper, type MetricsRecorder, type Net, type None, type Optional, type PrefetchedIntent, PrefetchedIntents, type RenderMode, type RouteDefinition, type RouteMatch, Router, type Storage, buildUrl, createPrefetchedIntentsFromDom, defineRoutes, deserializeServerData, generateUuid, getBaseUrl, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, mapEach, pipe, pipeAsync, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, removeHost, removeQueryParams, removeScheme, resetFilterCache, shouldLog, stableStringify, startBrowserApp, tryScroll };
|
|
904
|
+
export { ACTION_KINDS, type Action, ActionDispatcher, type ActionHandler, type ActionHandlerDependencies, type AfterLoadGuard, type AsyncMapper, BaseController, type BaseItem, BaseLogger, type BasePage, type BaseShelf, type BeforeLoadGuard, type BrowserAppConfig, type BrowserContextOptions, CompositeLogger, CompositeLoggerFactory, type CompoundAction, ConsoleLogger, ConsoleLoggerFactory, Container, DEP_KEYS, type DenyResult, type ExternalUrlAction, type ExternalUrlDependencies, type FeatureFlags, type FlowAction, type FlowActionCallbacks, type FlowActionDependencies, Framework, type FrameworkConfig, History, HttpClient, type HttpClientConfig, HttpError, type Intent, type IntentController, IntentDispatcher, type Locale, type Logger, type LoggerFactory, type Logger as LoggerInterface, LruMap, type Mapper, type MetricsRecorder, type MiddlewareResult, type NavigationContext, type Net, type NextResult, type None, type Optional, type PostLoadContext, type PrefetchedIntent, PrefetchedIntents, type RedirectResult, type RenderMode, type RewriteResult, type RouteAddOptions, type RouteDefinition, type RouteMatch, Router, type ServerContextOptions, type Storage, buildUrl, createBrowserContext, createPrefetchedIntentsFromDom, createServerContext, defineRoutes, deny, deserializeServerData, generateUuid, getBaseUrl, isCompoundAction, isExternalUrlAction, isFlowAction, isNone, isSome, makeDependencies, makeExternalUrlAction, makeFlowAction, mapEach, next, pipe, pipeAsync, redirect, registerActionHandlers, registerExternalUrlHandler, registerFlowActionHandler, removeHost, removeQueryParams, removeScheme, resetFilterCache, rewrite, runAfterLoadGuards, runBeforeLoadGuards, shouldLog, stableStringify, startBrowserApp, tryScroll };
|
package/dist/browser.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
registerFlowActionHandler,
|
|
8
8
|
startBrowserApp,
|
|
9
9
|
tryScroll
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-4PPCVAKZ.js";
|
|
11
11
|
import {
|
|
12
12
|
ACTION_KINDS,
|
|
13
13
|
ActionDispatcher,
|
|
@@ -27,7 +27,10 @@ import {
|
|
|
27
27
|
PrefetchedIntents,
|
|
28
28
|
Router,
|
|
29
29
|
buildUrl,
|
|
30
|
+
createBrowserContext,
|
|
31
|
+
createServerContext,
|
|
30
32
|
defineRoutes,
|
|
33
|
+
deny,
|
|
31
34
|
generateUuid,
|
|
32
35
|
getBaseUrl,
|
|
33
36
|
isCompoundAction,
|
|
@@ -39,15 +42,20 @@ import {
|
|
|
39
42
|
makeExternalUrlAction,
|
|
40
43
|
makeFlowAction,
|
|
41
44
|
mapEach,
|
|
45
|
+
next,
|
|
42
46
|
pipe,
|
|
43
47
|
pipeAsync,
|
|
48
|
+
redirect,
|
|
44
49
|
removeHost,
|
|
45
50
|
removeQueryParams,
|
|
46
51
|
removeScheme,
|
|
47
52
|
resetFilterCache,
|
|
53
|
+
rewrite,
|
|
54
|
+
runAfterLoadGuards,
|
|
55
|
+
runBeforeLoadGuards,
|
|
48
56
|
shouldLog,
|
|
49
57
|
stableStringify
|
|
50
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-SDPWQT2T.js";
|
|
51
59
|
export {
|
|
52
60
|
ACTION_KINDS,
|
|
53
61
|
ActionDispatcher,
|
|
@@ -68,8 +76,11 @@ export {
|
|
|
68
76
|
PrefetchedIntents,
|
|
69
77
|
Router,
|
|
70
78
|
buildUrl,
|
|
79
|
+
createBrowserContext,
|
|
71
80
|
createPrefetchedIntentsFromDom,
|
|
81
|
+
createServerContext,
|
|
72
82
|
defineRoutes,
|
|
83
|
+
deny,
|
|
73
84
|
deserializeServerData,
|
|
74
85
|
generateUuid,
|
|
75
86
|
getBaseUrl,
|
|
@@ -82,8 +93,10 @@ export {
|
|
|
82
93
|
makeExternalUrlAction,
|
|
83
94
|
makeFlowAction,
|
|
84
95
|
mapEach,
|
|
96
|
+
next,
|
|
85
97
|
pipe,
|
|
86
98
|
pipeAsync,
|
|
99
|
+
redirect,
|
|
87
100
|
registerActionHandlers,
|
|
88
101
|
registerExternalUrlHandler,
|
|
89
102
|
registerFlowActionHandler,
|
|
@@ -91,6 +104,9 @@ export {
|
|
|
91
104
|
removeQueryParams,
|
|
92
105
|
removeScheme,
|
|
93
106
|
resetFilterCache,
|
|
107
|
+
rewrite,
|
|
108
|
+
runAfterLoadGuards,
|
|
109
|
+
runBeforeLoadGuards,
|
|
94
110
|
shouldLog,
|
|
95
111
|
stableStringify,
|
|
96
112
|
startBrowserApp,
|
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
Framework,
|
|
5
5
|
LruMap,
|
|
6
6
|
PrefetchedIntents,
|
|
7
|
+
createBrowserContext,
|
|
7
8
|
generateUuid
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-SDPWQT2T.js";
|
|
9
10
|
|
|
10
11
|
// ../browser/src/action-handlers/external-url-action.ts
|
|
11
12
|
function registerExternalUrlHandler(deps) {
|
|
@@ -169,31 +170,49 @@ function registerFlowActionHandler(deps) {
|
|
|
169
170
|
const { framework, log, callbacks, updateApp } = deps;
|
|
170
171
|
let isFirstPage = true;
|
|
171
172
|
let navigationId = 0;
|
|
173
|
+
const MAX_REDIRECTS = 5;
|
|
172
174
|
const defaultGetScrollable = () => document.getElementById("scrollable-page-override") || document.getElementById("scrollable-page") || document.documentElement;
|
|
173
175
|
const history = new History(log, {
|
|
174
176
|
getScrollablePageElement: deps.getScrollablePageElement ?? defaultGetScrollable
|
|
175
177
|
});
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const match2 = framework.routeUrl(url);
|
|
182
|
-
if (match2) {
|
|
183
|
-
const page = await framework.dispatch(
|
|
184
|
-
match2.intent
|
|
185
|
-
);
|
|
186
|
-
callbacks.onModal(page);
|
|
187
|
-
}
|
|
178
|
+
async function navigateTo(url, redirectCount, thisNav) {
|
|
179
|
+
if (redirectCount >= MAX_REDIRECTS) {
|
|
180
|
+
log.error(
|
|
181
|
+
`Navigation redirect loop detected (${MAX_REDIRECTS} redirects), stopping at: ${url}`
|
|
182
|
+
);
|
|
188
183
|
return;
|
|
189
184
|
}
|
|
190
|
-
const thisNav = ++navigationId;
|
|
191
185
|
const shouldReplace = isFirstPage || url === window.location.pathname + window.location.search;
|
|
192
186
|
const match = framework.routeUrl(url);
|
|
193
187
|
if (!match) {
|
|
194
188
|
log.warn(`FlowAction: no route for ${url}`);
|
|
195
189
|
return;
|
|
196
190
|
}
|
|
191
|
+
const navCtx = createBrowserContext({
|
|
192
|
+
url,
|
|
193
|
+
intent: match.intent,
|
|
194
|
+
container: framework.container
|
|
195
|
+
});
|
|
196
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
197
|
+
navCtx,
|
|
198
|
+
match.beforeGuards
|
|
199
|
+
);
|
|
200
|
+
if (beforeResult.kind === "redirect") {
|
|
201
|
+
log.debug(`beforeLoad \u2192 redirect to ${beforeResult.url}`);
|
|
202
|
+
await navigateTo(beforeResult.url, redirectCount + 1, thisNav);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (beforeResult.kind === "deny") {
|
|
206
|
+
log.warn(
|
|
207
|
+
`beforeLoad \u2192 denied (${beforeResult.status}): ${beforeResult.message}`
|
|
208
|
+
);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (beforeResult.kind === "rewrite") {
|
|
212
|
+
log.debug(`beforeLoad \u2192 rewrite to ${beforeResult.url}`);
|
|
213
|
+
await navigateTo(beforeResult.url, redirectCount + 1, thisNav);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
197
216
|
const pagePromise = framework.dispatch(
|
|
198
217
|
match.intent
|
|
199
218
|
);
|
|
@@ -209,12 +228,33 @@ function registerFlowActionHandler(deps) {
|
|
|
209
228
|
history.beforeTransition();
|
|
210
229
|
updateApp({
|
|
211
230
|
page: pagePromise.then(
|
|
212
|
-
(page) => {
|
|
231
|
+
async (page) => {
|
|
213
232
|
if (thisNav !== navigationId) {
|
|
214
233
|
log.info("FlowAction commit superseded", url);
|
|
215
234
|
return page;
|
|
216
235
|
}
|
|
217
|
-
const
|
|
236
|
+
const postCtx = {
|
|
237
|
+
...navCtx,
|
|
238
|
+
page
|
|
239
|
+
};
|
|
240
|
+
const afterResult = await framework.runAfterLoad(
|
|
241
|
+
postCtx,
|
|
242
|
+
match.afterGuards
|
|
243
|
+
);
|
|
244
|
+
if (afterResult.kind === "redirect") {
|
|
245
|
+
log.debug(`afterLoad \u2192 redirect to ${afterResult.url}`);
|
|
246
|
+
navigateTo(afterResult.url, redirectCount + 1, thisNav);
|
|
247
|
+
return page;
|
|
248
|
+
}
|
|
249
|
+
let canonicalURL = url;
|
|
250
|
+
if (afterResult.kind === "rewrite") {
|
|
251
|
+
canonicalURL = afterResult.url;
|
|
252
|
+
log.debug(`afterLoad \u2192 rewrite URL to ${canonicalURL}`);
|
|
253
|
+
}
|
|
254
|
+
if (afterResult.kind === "deny") {
|
|
255
|
+
log.warn(`afterLoad \u2192 denied (${afterResult.status})`);
|
|
256
|
+
return page;
|
|
257
|
+
}
|
|
218
258
|
if (shouldReplace) {
|
|
219
259
|
history.replaceState({ page }, canonicalURL);
|
|
220
260
|
} else {
|
|
@@ -244,6 +284,23 @@ function registerFlowActionHandler(deps) {
|
|
|
244
284
|
isFirstPage
|
|
245
285
|
});
|
|
246
286
|
isFirstPage = false;
|
|
287
|
+
}
|
|
288
|
+
framework.onAction(ACTION_KINDS.FLOW, async (action) => {
|
|
289
|
+
const flowAction = action;
|
|
290
|
+
const url = flowAction.url;
|
|
291
|
+
log.debug(`FlowAction \u2192 ${url}`);
|
|
292
|
+
if (flowAction.presentationContext === "modal") {
|
|
293
|
+
const match = framework.routeUrl(url);
|
|
294
|
+
if (match) {
|
|
295
|
+
const page = await framework.dispatch(
|
|
296
|
+
match.intent
|
|
297
|
+
);
|
|
298
|
+
callbacks.onModal(page);
|
|
299
|
+
}
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const thisNav = ++navigationId;
|
|
303
|
+
await navigateTo(url, 0, thisNav);
|
|
247
304
|
});
|
|
248
305
|
history.onPopState(async (url, cachedState) => {
|
|
249
306
|
log.debug(`popstate \u2192 ${url}, cached=${!!cachedState}`);
|
|
@@ -268,6 +325,30 @@ function registerFlowActionHandler(deps) {
|
|
|
268
325
|
});
|
|
269
326
|
return;
|
|
270
327
|
}
|
|
328
|
+
const navCtx = createBrowserContext({
|
|
329
|
+
url: parsed.pathname + parsed.search,
|
|
330
|
+
intent: routeMatch.intent,
|
|
331
|
+
container: framework.container
|
|
332
|
+
});
|
|
333
|
+
const beforeResult = await framework.runBeforeLoad(
|
|
334
|
+
navCtx,
|
|
335
|
+
routeMatch.beforeGuards
|
|
336
|
+
);
|
|
337
|
+
if (beforeResult.kind === "redirect") {
|
|
338
|
+
log.debug(`popstate beforeLoad \u2192 redirect to ${beforeResult.url}`);
|
|
339
|
+
const thisNav = ++navigationId;
|
|
340
|
+
await navigateTo(beforeResult.url, 0, thisNav);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
if (beforeResult.kind === "deny" || beforeResult.kind === "rewrite") {
|
|
344
|
+
if (beforeResult.kind === "deny") {
|
|
345
|
+
log.warn(`popstate beforeLoad \u2192 denied`);
|
|
346
|
+
} else {
|
|
347
|
+
const thisNav = ++navigationId;
|
|
348
|
+
await navigateTo(beforeResult.url, 0, thisNav);
|
|
349
|
+
}
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
271
352
|
const pagePromise = framework.dispatch(
|
|
272
353
|
routeMatch.intent
|
|
273
354
|
);
|
|
@@ -379,4 +460,4 @@ export {
|
|
|
379
460
|
createPrefetchedIntentsFromDom,
|
|
380
461
|
startBrowserApp
|
|
381
462
|
};
|
|
382
|
-
//# sourceMappingURL=chunk-
|
|
463
|
+
//# sourceMappingURL=chunk-4PPCVAKZ.js.map
|