@pactor-app/app 1.18.0 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/dist/index.cjs +614 -0
- package/dist/index.d.cts +262 -3
- package/dist/index.d.ts +262 -3
- package/dist/index.js +609 -0
- package/package.json +9 -9
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Registry, I18nMessages, PageDsl, DslSourceRef } from '@pactor-app/core';
|
|
1
|
+
import { Registry, I18nMessages, PageDsl, DslSourceRef, DslNode } from '@pactor-app/core';
|
|
2
2
|
import { InteractionProviderProps, OverlayHostProps, OverlayManager, UiBridge } from '@pactor-app/ui/interaction';
|
|
3
3
|
import { LayoutRegistry, AdminLayoutConfig } from '@pactor-app/ui/layout';
|
|
4
4
|
import { PermissionStore } from '@pactor-app/permission';
|
|
5
5
|
import { BootstrapResource, DslResourceLoader } from '@pactor-app/resource';
|
|
6
|
-
import { NavigationBridge, NavigationLocation, NavigationListener, MenuRegistry, RouteContext } from '@pactor-app/router';
|
|
6
|
+
import { NavigationBridge, NavigationLocation, NavigationListener, MenuRegistry, RouteContext, MenuItem } from '@pactor-app/router';
|
|
7
7
|
import { HttpRequestConfig, ActionHandler, ServiceHandler, HttpAdapter, PageRuntime, PermissionAdapter } from '@pactor-app/runtime';
|
|
8
8
|
import * as react from 'react';
|
|
9
9
|
import { ComponentType, ReactNode, Component, ErrorInfo } from 'react';
|
|
@@ -366,4 +366,263 @@ declare function createPactorPage(options?: PactorPageOptions): ComponentType<Pa
|
|
|
366
366
|
*/
|
|
367
367
|
declare function PactorPage(props: PactorPageProps & PactorPageOptions): react.JSX.Element;
|
|
368
368
|
|
|
369
|
-
|
|
369
|
+
/**
|
|
370
|
+
* SitemapApp 缺省动作(宿主 actions 同名覆盖):
|
|
371
|
+
* 常见动作开箱即用,无需每个项目重复扩展。
|
|
372
|
+
*
|
|
373
|
+
* - app.reload:整页重载 / 跳转。登录 / 登出后 sitemap 端点需按新会话
|
|
374
|
+
* 重新裁剪内容(SPA 导航不触发重取),params.to 缺省跳 '/'
|
|
375
|
+
* - service.call:调用已注册服务(params.service 服务名,params.params
|
|
376
|
+
* 入参,表达式求值后传入)。request 动作仅覆盖 HTTP 出口,
|
|
377
|
+
* 服务层调用经此桥接
|
|
378
|
+
*/
|
|
379
|
+
declare const defaultSitemapActions: Record<string, ActionHandler>;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Sitemap 对象结构(design/dynamic-page.md,方案 B):
|
|
383
|
+
* 扁平 pages + 独立 menus + DSL 布局 layouts。
|
|
384
|
+
* 服务端按会话裁剪内容(匿名 / 角色),对象本身不为角色建模。
|
|
385
|
+
*/
|
|
386
|
+
/** 布局定义:DSL 描述外壳结构,PageOutlet 组件为页面内容出口。
|
|
387
|
+
* 不套 PageDsl 的 page 包装——id 即 layouts 的键,无重复声明 */
|
|
388
|
+
interface LayoutDsl {
|
|
389
|
+
dsl: string;
|
|
390
|
+
body: DslNode;
|
|
391
|
+
}
|
|
392
|
+
/** 页面定义:id 主键;pageDsl 缺省 → loadPage(id) 懒加载 */
|
|
393
|
+
interface SitemapPageEntry {
|
|
394
|
+
id: string;
|
|
395
|
+
/** 页面 url,支持 /reports/:id 参数 */
|
|
396
|
+
path: string;
|
|
397
|
+
title: string;
|
|
398
|
+
/** 单页版本,参与缓存键 id@version */
|
|
399
|
+
version?: number;
|
|
400
|
+
/** 内联页面 DSL;缺省 = 懒加载 */
|
|
401
|
+
pageDsl?: PageDsl;
|
|
402
|
+
}
|
|
403
|
+
/** 菜单/路由条目:MenuItem + layout 引用 + public 标记。
|
|
404
|
+
* type: 'page' 且带 pageId 时,path / title 缺省从引用页面继承,
|
|
405
|
+
* 仅在导航与页面分叉时显式覆写;group / link 只出现在 menus 中 */
|
|
406
|
+
interface SitemapMenuItem extends MenuItem {
|
|
407
|
+
/** 引用 layouts 的键;缺省用顶层 layout */
|
|
408
|
+
layout?: string;
|
|
409
|
+
/** 免登录可访问(登录/注册/落地页) */
|
|
410
|
+
public?: boolean;
|
|
411
|
+
children?: SitemapMenuItem[];
|
|
412
|
+
}
|
|
413
|
+
interface SitemapResource extends BootstrapResource {
|
|
414
|
+
/** 应用级缺省布局名,引用 layouts 的键 */
|
|
415
|
+
layout?: string;
|
|
416
|
+
/** 匿名访问控制:未登录访问非 public 页时重定向到 loginPath */
|
|
417
|
+
auth?: {
|
|
418
|
+
loginPath?: string;
|
|
419
|
+
};
|
|
420
|
+
layouts: Record<string, LayoutDsl>;
|
|
421
|
+
pages: SitemapPageEntry[];
|
|
422
|
+
menus: SitemapMenuItem[];
|
|
423
|
+
}
|
|
424
|
+
/** 可渲染路由匹配结果(resolveSitemapRoute 产物) */
|
|
425
|
+
interface SitemapRouteMatch {
|
|
426
|
+
pageId: string;
|
|
427
|
+
layoutName: string;
|
|
428
|
+
/** 菜单高亮 key:activeMenu 指向的菜单项 path(缺省自身 path) */
|
|
429
|
+
highlightKey: string;
|
|
430
|
+
params: Record<string, string>;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
interface FetchSitemapOptions {
|
|
434
|
+
/** fetch 实现(缺省全局 fetch;SSR / 测试可注入) */
|
|
435
|
+
fetcher?: typeof fetch;
|
|
436
|
+
/** 接口基准地址:sources 为相对路径时以此为基准补全 */
|
|
437
|
+
baseUrl?: string;
|
|
438
|
+
/** HTTP 钩子:与页面运行时同一套 request / response 加工 */
|
|
439
|
+
httpHooks?: PactorHttpHooks;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* 拉取并合并多个 sitemap 源(design/dynamic-page.md):
|
|
443
|
+
* pages / menus / layouts 按键合并(id / path 冲突后源覆盖前源并告警),
|
|
444
|
+
* app / user / permissions / auth 取第一个源。
|
|
445
|
+
*/
|
|
446
|
+
declare function fetchSitemap(sources: string[], options?: FetchSitemapOptions): Promise<SitemapResource>;
|
|
447
|
+
|
|
448
|
+
interface SitemapLoaderOptions {
|
|
449
|
+
/** 懒加载页面端点(pages[].pageDsl 缺省时按 id 获取),缺省 /api/pages/{id} */
|
|
450
|
+
pageEndpoint?: (pageId: string) => string;
|
|
451
|
+
/** fetch 实现(缺省全局 fetch) */
|
|
452
|
+
fetcher?: typeof fetch;
|
|
453
|
+
/** 会话服务名(注入每个页面的 dataSource),缺省 'session.context' */
|
|
454
|
+
sessionService?: string;
|
|
455
|
+
/** 接口基准地址:pageEndpoint 返回相对路径时以此为基准补全 */
|
|
456
|
+
baseUrl?: string;
|
|
457
|
+
/** HTTP 钩子:与页面运行时同一套 request / response 加工 */
|
|
458
|
+
httpHooks?: PactorHttpHooks;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* SitemapDslLoader(design/dynamic-page.md 落地影响 #1):
|
|
462
|
+
* 内联 pageDsl 直接命中;缺省项经页面端点懒加载。
|
|
463
|
+
* 缓存键 id@version——同一版本只取一次。
|
|
464
|
+
* 每个页面注入 session dataSource(${data.session.*}),页面自行声明
|
|
465
|
+
* 同名 dataSource 时以页面为准。
|
|
466
|
+
*/
|
|
467
|
+
declare function createSitemapLoader(sitemap: SitemapResource, options?: SitemapLoaderOptions): DslResourceLoader;
|
|
468
|
+
|
|
469
|
+
/** 路由解析结果:菜单命中情况 + 可渲染路由(404 判定) */
|
|
470
|
+
interface SitemapRouteResolution {
|
|
471
|
+
/** 命中的菜单项(未命中为 null) */
|
|
472
|
+
menu: SitemapMenuItem | null;
|
|
473
|
+
/** 可渲染路由;菜单未命中或无 pageId(group / link)时为 null → 404 */
|
|
474
|
+
route: SitemapRouteMatch | null;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* 路由解析(纯函数):菜单命中、布局名、activeMenu 高亮 key 一次算清。
|
|
478
|
+
* 布局名解析链:menu.layout → 顶层 layout → layouts 首键。
|
|
479
|
+
* 高亮 key:activeMenu 指向其他菜单 id 时高亮该项(隐藏页场景),
|
|
480
|
+
* key 与 toSitemapNavItems 一致(path ?? id)。
|
|
481
|
+
*/
|
|
482
|
+
declare function resolveSitemapRoute(sitemap: SitemapResource, registry: MenuRegistry, pathname: string): SitemapRouteResolution;
|
|
483
|
+
/** 守卫判定:放行或重定向 */
|
|
484
|
+
type SitemapGuardDecision = {
|
|
485
|
+
allow: true;
|
|
486
|
+
} | {
|
|
487
|
+
allow: false;
|
|
488
|
+
redirectTo: string;
|
|
489
|
+
};
|
|
490
|
+
interface SitemapGuardContext {
|
|
491
|
+
sitemap: SitemapResource;
|
|
492
|
+
pathname: string;
|
|
493
|
+
/** 命中的菜单项(未命中为 null) */
|
|
494
|
+
menu: SitemapMenuItem | null;
|
|
495
|
+
}
|
|
496
|
+
/** 访问守卫:每次路由变化时求值;返回重定向时组件执行 navigate */
|
|
497
|
+
type SitemapGuard = (context: SitemapGuardContext) => SitemapGuardDecision;
|
|
498
|
+
/**
|
|
499
|
+
* 缺省守卫(匿名访问控制):未登录访问非 public 页(含未命中路径)→
|
|
500
|
+
* 重定向 auth.loginPath(缺省 /login)。
|
|
501
|
+
*/
|
|
502
|
+
declare const defaultSitemapGuard: SitemapGuard;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* SitemapApp(design/dynamic-page.md):sitemap 驱动的动态页面应用组件。
|
|
506
|
+
* 简单配置即可实现动态页面。两种路由模式:
|
|
507
|
+
* - 纯前端 SPA:不传路由 props,内置浏览器路由(History API + popstate);
|
|
508
|
+
* - 宿主路由(Next App Router / react-router / 任意宿主):注入 pathname / navigate。
|
|
509
|
+
*
|
|
510
|
+
* ```tsx
|
|
511
|
+
* <SitemapApp
|
|
512
|
+
* sources={['/api/sitemap']}
|
|
513
|
+
* baseUrl="https://api.example.com"
|
|
514
|
+
* pathname={usePathname()}
|
|
515
|
+
* navigate={(to) => router.push(to)}
|
|
516
|
+
* services={{ 'auth.login': login }}
|
|
517
|
+
* />
|
|
518
|
+
* ```
|
|
519
|
+
*
|
|
520
|
+
* baseUrl 可选:sources / pageEndpoint 只写相对路径时以此为基准补全。
|
|
521
|
+
*
|
|
522
|
+
* 内置:多源拉取合并、menus×pages 继承、MenuRegistry 路由解析、访问守卫
|
|
523
|
+
* (缺省匿名守卫:非 public 且无 user → navigate 到 auth.loginPath,
|
|
524
|
+
* 可经 guard prop 替换)、DSL 布局渲染
|
|
525
|
+
* (PageOutlet 页面出口 + SitemapMenu 选中态 / activeMenu 高亮)、
|
|
526
|
+
* 页面内联 / 懒加载(id@version 缓存)、session.context 服务桥
|
|
527
|
+
* (${data.session.*})、缺省动作(app.reload / service.call)。
|
|
528
|
+
*
|
|
529
|
+
* 布局常驻:切换导航(同布局名)时仅 PageOutlet 内页面随路由重建。
|
|
530
|
+
*/
|
|
531
|
+
interface SitemapAppProps {
|
|
532
|
+
/** sitemap 接口 URL 列表(多源合并,冲突后源覆盖前源);相对路径以 baseUrl 补全 */
|
|
533
|
+
sources: string[];
|
|
534
|
+
/** 接口基准地址:sources / pageEndpoint 中的相对路径以此为基准补全 */
|
|
535
|
+
baseUrl?: string;
|
|
536
|
+
/** 当前路径(宿主路由注入,如 Next usePathname);缺省用内置浏览器路由 */
|
|
537
|
+
pathname?: string;
|
|
538
|
+
/** 站内导航实现(如 Next router.push);http(s) 外链自动新标签打开;
|
|
539
|
+
* 缺省用内置浏览器路由(History API) */
|
|
540
|
+
navigate?: (to: string) => void;
|
|
541
|
+
/** 当前 query(DSL ${route.query.x} 可读);缺省自 location.search 解析 */
|
|
542
|
+
query?: Record<string, string>;
|
|
543
|
+
/** 懒加载页面端点,缺省 /api/pages/{id} */
|
|
544
|
+
pageEndpoint?: SitemapLoaderOptions['pageEndpoint'];
|
|
545
|
+
/** 业务服务(auth.login 等);session.context 由组件自动注册 */
|
|
546
|
+
services?: Record<string, ServiceHandler>;
|
|
547
|
+
/** 业务动作;框架内置 app.reload / service.call 默认值,同名覆盖 */
|
|
548
|
+
actions?: Record<string, ActionHandler>;
|
|
549
|
+
/** 业务组件(同名覆盖内建;PageOutlet / SitemapMenu 为布局保留名) */
|
|
550
|
+
components?: Record<string, unknown>;
|
|
551
|
+
/** HTTP 钩子:所有 HTTP 出口(sitemap 源 / 页面端点 / 页面运行时)的统一加工(跨域改写 / 拆包) */
|
|
552
|
+
httpAdapter?: PactorHttpHooks;
|
|
553
|
+
/** fetch 实现(缺省全局 fetch;SSR / 测试可注入) */
|
|
554
|
+
fetcher?: FetchSitemapOptions['fetcher'];
|
|
555
|
+
/** 访问守卫(缺省 defaultSitemapGuard:匿名访问非 public 页 → 重定向 auth.loginPath) */
|
|
556
|
+
guard?: SitemapGuard;
|
|
557
|
+
/** 会话服务名(缺省 session.context) */
|
|
558
|
+
sessionService?: string;
|
|
559
|
+
/** 加载中视图 */
|
|
560
|
+
loading?: ReactNode;
|
|
561
|
+
/** sitemap 加载失败视图 */
|
|
562
|
+
renderError?: (error: Error) => ReactNode;
|
|
563
|
+
/** 路由未命中视图 */
|
|
564
|
+
renderNotFound?: (path: string) => ReactNode;
|
|
565
|
+
}
|
|
566
|
+
declare function SitemapApp(props: SitemapAppProps): react.JSX.Element | null;
|
|
567
|
+
|
|
568
|
+
/** createHttpHooks 配置 */
|
|
569
|
+
interface CreateHttpHooksOptions {
|
|
570
|
+
/** 项目内代理前缀:传入后跨域绝对地址改写到此前缀(由宿主服务端
|
|
571
|
+
* 转发);缺省不改写——服务端已开通 CORS,浏览器直连 */
|
|
572
|
+
proxyPrefix?: string;
|
|
573
|
+
/** 公共头注入(Authorization / 租户头等),对象或函数(每次请求求值) */
|
|
574
|
+
headers?: Record<string, string> | (() => Record<string, string>);
|
|
575
|
+
/** 响应拆包:缺省按 { code, data, message } 包裹协议处理(拆出 data,
|
|
576
|
+
* 非 0 抛错);后端不包裹时传 false 关闭 */
|
|
577
|
+
envelope?: boolean;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* 默认 HTTP 钩子(常用协议开箱即用):
|
|
581
|
+
* - request:缺省不改写地址(假定服务端已开通 CORS,浏览器直连);
|
|
582
|
+
* 传 proxyPrefix 时跨域绝对地址(origin ≠ 页面源)改写到项目内
|
|
583
|
+
* 代理前缀(path + query 保留),由宿主服务端代理转发
|
|
584
|
+
* (Vite server.proxy / Next rewrites / nginx);可注入公共头
|
|
585
|
+
* - response:{ code, data, message } 包裹结构拆包为 data,非 0 抛错
|
|
586
|
+
* (DSL 动作按失败处理);非包裹结构原样透传
|
|
587
|
+
*
|
|
588
|
+
* 后端协议不同(包裹结构 / 错误码约定)时自行实现 PactorHttpHooks。
|
|
589
|
+
*/
|
|
590
|
+
declare function createHttpHooks(options?: CreateHttpHooksOptions): PactorHttpHooks;
|
|
591
|
+
/**
|
|
592
|
+
* 把 PactorHttpHooks 包装到 fetcher 上:sitemap 源 / 页面端点等框架自发
|
|
593
|
+
* 请求与页面运行时走同一套 HTTP 加工(跨域改写 / 鉴权头 / 响应拆包)。
|
|
594
|
+
* response 钩子仅作用于 2xx(错误响应原样返回,由调用方判定 HTTP 错误)。
|
|
595
|
+
*/
|
|
596
|
+
declare function withHttpHooks(fetcher: typeof fetch, hooks?: PactorHttpHooks): typeof fetch;
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* menus × pages 合并:type: 'page' 且带 pageId 的条目缺省从引用页面
|
|
600
|
+
* 继承 path / title(仅分叉时覆写);group / link 原样透传。
|
|
601
|
+
* 产物可直接 new MenuRegistry(...) 做路由匹配。
|
|
602
|
+
*/
|
|
603
|
+
declare function mergeSitemapMenus(sitemap: SitemapResource): SitemapMenuItem[];
|
|
604
|
+
/** ui Menu 组件 items 形态(可见菜单树 → 导航数据;key = 路径) */
|
|
605
|
+
interface SitemapNavItem {
|
|
606
|
+
key: string;
|
|
607
|
+
label: string;
|
|
608
|
+
icon?: string;
|
|
609
|
+
disabled?: boolean;
|
|
610
|
+
children?: SitemapNavItem[];
|
|
611
|
+
}
|
|
612
|
+
declare function toSitemapNavItems(menuTree: MenuItem[]): SitemapNavItem[];
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* 会话上下文(session.context 服务返回值):布局 / 页面 DSL 经
|
|
616
|
+
* service dataSource 消费(${data.session.*})。
|
|
617
|
+
* 框架原生 user / menus 作用域属设计目标(design/dynamic-page.md
|
|
618
|
+
* 落地影响 #3),当前经服务桥实现。
|
|
619
|
+
*/
|
|
620
|
+
interface SitemapSessionContext {
|
|
621
|
+
user?: Record<string, unknown>;
|
|
622
|
+
app: Record<string, unknown>;
|
|
623
|
+
menus: SitemapNavItem[];
|
|
624
|
+
}
|
|
625
|
+
/** 注册会话桥服务(缺省名 session.context,与 loader 注入的 dataSource 对应) */
|
|
626
|
+
declare function createSitemapSessionServices(session: SitemapSessionContext, serviceName?: string): Record<string, ServiceHandler>;
|
|
627
|
+
|
|
628
|
+
export { Application, type ApplicationProps, type AuthTokenProvider, type CreateHttpHooksOptions, DslPageLoader, type DslPageLoaderProps, type FetchSitemapOptions, type LayoutDsl, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, SitemapApp, type SitemapAppProps, type SitemapGuard, type SitemapGuardContext, type SitemapGuardDecision, type SitemapLoaderOptions, type SitemapMenuItem, type SitemapNavItem, type SitemapPageEntry, type SitemapResource, type SitemapRouteMatch, type SitemapRouteResolution, type SitemapSessionContext, createHttpHooks, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, createSitemapLoader, createSitemapSessionServices, defaultSitemapActions, defaultSitemapGuard, fetchSitemap, mergeSitemapMenus, resolveSitemapRoute, toSitemapNavItems, withHttpHooks, wrapHttpAdapter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Registry, I18nMessages, PageDsl, DslSourceRef } from '@pactor-app/core';
|
|
1
|
+
import { Registry, I18nMessages, PageDsl, DslSourceRef, DslNode } from '@pactor-app/core';
|
|
2
2
|
import { InteractionProviderProps, OverlayHostProps, OverlayManager, UiBridge } from '@pactor-app/ui/interaction';
|
|
3
3
|
import { LayoutRegistry, AdminLayoutConfig } from '@pactor-app/ui/layout';
|
|
4
4
|
import { PermissionStore } from '@pactor-app/permission';
|
|
5
5
|
import { BootstrapResource, DslResourceLoader } from '@pactor-app/resource';
|
|
6
|
-
import { NavigationBridge, NavigationLocation, NavigationListener, MenuRegistry, RouteContext } from '@pactor-app/router';
|
|
6
|
+
import { NavigationBridge, NavigationLocation, NavigationListener, MenuRegistry, RouteContext, MenuItem } from '@pactor-app/router';
|
|
7
7
|
import { HttpRequestConfig, ActionHandler, ServiceHandler, HttpAdapter, PageRuntime, PermissionAdapter } from '@pactor-app/runtime';
|
|
8
8
|
import * as react from 'react';
|
|
9
9
|
import { ComponentType, ReactNode, Component, ErrorInfo } from 'react';
|
|
@@ -366,4 +366,263 @@ declare function createPactorPage(options?: PactorPageOptions): ComponentType<Pa
|
|
|
366
366
|
*/
|
|
367
367
|
declare function PactorPage(props: PactorPageProps & PactorPageOptions): react.JSX.Element;
|
|
368
368
|
|
|
369
|
-
|
|
369
|
+
/**
|
|
370
|
+
* SitemapApp 缺省动作(宿主 actions 同名覆盖):
|
|
371
|
+
* 常见动作开箱即用,无需每个项目重复扩展。
|
|
372
|
+
*
|
|
373
|
+
* - app.reload:整页重载 / 跳转。登录 / 登出后 sitemap 端点需按新会话
|
|
374
|
+
* 重新裁剪内容(SPA 导航不触发重取),params.to 缺省跳 '/'
|
|
375
|
+
* - service.call:调用已注册服务(params.service 服务名,params.params
|
|
376
|
+
* 入参,表达式求值后传入)。request 动作仅覆盖 HTTP 出口,
|
|
377
|
+
* 服务层调用经此桥接
|
|
378
|
+
*/
|
|
379
|
+
declare const defaultSitemapActions: Record<string, ActionHandler>;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Sitemap 对象结构(design/dynamic-page.md,方案 B):
|
|
383
|
+
* 扁平 pages + 独立 menus + DSL 布局 layouts。
|
|
384
|
+
* 服务端按会话裁剪内容(匿名 / 角色),对象本身不为角色建模。
|
|
385
|
+
*/
|
|
386
|
+
/** 布局定义:DSL 描述外壳结构,PageOutlet 组件为页面内容出口。
|
|
387
|
+
* 不套 PageDsl 的 page 包装——id 即 layouts 的键,无重复声明 */
|
|
388
|
+
interface LayoutDsl {
|
|
389
|
+
dsl: string;
|
|
390
|
+
body: DslNode;
|
|
391
|
+
}
|
|
392
|
+
/** 页面定义:id 主键;pageDsl 缺省 → loadPage(id) 懒加载 */
|
|
393
|
+
interface SitemapPageEntry {
|
|
394
|
+
id: string;
|
|
395
|
+
/** 页面 url,支持 /reports/:id 参数 */
|
|
396
|
+
path: string;
|
|
397
|
+
title: string;
|
|
398
|
+
/** 单页版本,参与缓存键 id@version */
|
|
399
|
+
version?: number;
|
|
400
|
+
/** 内联页面 DSL;缺省 = 懒加载 */
|
|
401
|
+
pageDsl?: PageDsl;
|
|
402
|
+
}
|
|
403
|
+
/** 菜单/路由条目:MenuItem + layout 引用 + public 标记。
|
|
404
|
+
* type: 'page' 且带 pageId 时,path / title 缺省从引用页面继承,
|
|
405
|
+
* 仅在导航与页面分叉时显式覆写;group / link 只出现在 menus 中 */
|
|
406
|
+
interface SitemapMenuItem extends MenuItem {
|
|
407
|
+
/** 引用 layouts 的键;缺省用顶层 layout */
|
|
408
|
+
layout?: string;
|
|
409
|
+
/** 免登录可访问(登录/注册/落地页) */
|
|
410
|
+
public?: boolean;
|
|
411
|
+
children?: SitemapMenuItem[];
|
|
412
|
+
}
|
|
413
|
+
interface SitemapResource extends BootstrapResource {
|
|
414
|
+
/** 应用级缺省布局名,引用 layouts 的键 */
|
|
415
|
+
layout?: string;
|
|
416
|
+
/** 匿名访问控制:未登录访问非 public 页时重定向到 loginPath */
|
|
417
|
+
auth?: {
|
|
418
|
+
loginPath?: string;
|
|
419
|
+
};
|
|
420
|
+
layouts: Record<string, LayoutDsl>;
|
|
421
|
+
pages: SitemapPageEntry[];
|
|
422
|
+
menus: SitemapMenuItem[];
|
|
423
|
+
}
|
|
424
|
+
/** 可渲染路由匹配结果(resolveSitemapRoute 产物) */
|
|
425
|
+
interface SitemapRouteMatch {
|
|
426
|
+
pageId: string;
|
|
427
|
+
layoutName: string;
|
|
428
|
+
/** 菜单高亮 key:activeMenu 指向的菜单项 path(缺省自身 path) */
|
|
429
|
+
highlightKey: string;
|
|
430
|
+
params: Record<string, string>;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
interface FetchSitemapOptions {
|
|
434
|
+
/** fetch 实现(缺省全局 fetch;SSR / 测试可注入) */
|
|
435
|
+
fetcher?: typeof fetch;
|
|
436
|
+
/** 接口基准地址:sources 为相对路径时以此为基准补全 */
|
|
437
|
+
baseUrl?: string;
|
|
438
|
+
/** HTTP 钩子:与页面运行时同一套 request / response 加工 */
|
|
439
|
+
httpHooks?: PactorHttpHooks;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* 拉取并合并多个 sitemap 源(design/dynamic-page.md):
|
|
443
|
+
* pages / menus / layouts 按键合并(id / path 冲突后源覆盖前源并告警),
|
|
444
|
+
* app / user / permissions / auth 取第一个源。
|
|
445
|
+
*/
|
|
446
|
+
declare function fetchSitemap(sources: string[], options?: FetchSitemapOptions): Promise<SitemapResource>;
|
|
447
|
+
|
|
448
|
+
interface SitemapLoaderOptions {
|
|
449
|
+
/** 懒加载页面端点(pages[].pageDsl 缺省时按 id 获取),缺省 /api/pages/{id} */
|
|
450
|
+
pageEndpoint?: (pageId: string) => string;
|
|
451
|
+
/** fetch 实现(缺省全局 fetch) */
|
|
452
|
+
fetcher?: typeof fetch;
|
|
453
|
+
/** 会话服务名(注入每个页面的 dataSource),缺省 'session.context' */
|
|
454
|
+
sessionService?: string;
|
|
455
|
+
/** 接口基准地址:pageEndpoint 返回相对路径时以此为基准补全 */
|
|
456
|
+
baseUrl?: string;
|
|
457
|
+
/** HTTP 钩子:与页面运行时同一套 request / response 加工 */
|
|
458
|
+
httpHooks?: PactorHttpHooks;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* SitemapDslLoader(design/dynamic-page.md 落地影响 #1):
|
|
462
|
+
* 内联 pageDsl 直接命中;缺省项经页面端点懒加载。
|
|
463
|
+
* 缓存键 id@version——同一版本只取一次。
|
|
464
|
+
* 每个页面注入 session dataSource(${data.session.*}),页面自行声明
|
|
465
|
+
* 同名 dataSource 时以页面为准。
|
|
466
|
+
*/
|
|
467
|
+
declare function createSitemapLoader(sitemap: SitemapResource, options?: SitemapLoaderOptions): DslResourceLoader;
|
|
468
|
+
|
|
469
|
+
/** 路由解析结果:菜单命中情况 + 可渲染路由(404 判定) */
|
|
470
|
+
interface SitemapRouteResolution {
|
|
471
|
+
/** 命中的菜单项(未命中为 null) */
|
|
472
|
+
menu: SitemapMenuItem | null;
|
|
473
|
+
/** 可渲染路由;菜单未命中或无 pageId(group / link)时为 null → 404 */
|
|
474
|
+
route: SitemapRouteMatch | null;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* 路由解析(纯函数):菜单命中、布局名、activeMenu 高亮 key 一次算清。
|
|
478
|
+
* 布局名解析链:menu.layout → 顶层 layout → layouts 首键。
|
|
479
|
+
* 高亮 key:activeMenu 指向其他菜单 id 时高亮该项(隐藏页场景),
|
|
480
|
+
* key 与 toSitemapNavItems 一致(path ?? id)。
|
|
481
|
+
*/
|
|
482
|
+
declare function resolveSitemapRoute(sitemap: SitemapResource, registry: MenuRegistry, pathname: string): SitemapRouteResolution;
|
|
483
|
+
/** 守卫判定:放行或重定向 */
|
|
484
|
+
type SitemapGuardDecision = {
|
|
485
|
+
allow: true;
|
|
486
|
+
} | {
|
|
487
|
+
allow: false;
|
|
488
|
+
redirectTo: string;
|
|
489
|
+
};
|
|
490
|
+
interface SitemapGuardContext {
|
|
491
|
+
sitemap: SitemapResource;
|
|
492
|
+
pathname: string;
|
|
493
|
+
/** 命中的菜单项(未命中为 null) */
|
|
494
|
+
menu: SitemapMenuItem | null;
|
|
495
|
+
}
|
|
496
|
+
/** 访问守卫:每次路由变化时求值;返回重定向时组件执行 navigate */
|
|
497
|
+
type SitemapGuard = (context: SitemapGuardContext) => SitemapGuardDecision;
|
|
498
|
+
/**
|
|
499
|
+
* 缺省守卫(匿名访问控制):未登录访问非 public 页(含未命中路径)→
|
|
500
|
+
* 重定向 auth.loginPath(缺省 /login)。
|
|
501
|
+
*/
|
|
502
|
+
declare const defaultSitemapGuard: SitemapGuard;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* SitemapApp(design/dynamic-page.md):sitemap 驱动的动态页面应用组件。
|
|
506
|
+
* 简单配置即可实现动态页面。两种路由模式:
|
|
507
|
+
* - 纯前端 SPA:不传路由 props,内置浏览器路由(History API + popstate);
|
|
508
|
+
* - 宿主路由(Next App Router / react-router / 任意宿主):注入 pathname / navigate。
|
|
509
|
+
*
|
|
510
|
+
* ```tsx
|
|
511
|
+
* <SitemapApp
|
|
512
|
+
* sources={['/api/sitemap']}
|
|
513
|
+
* baseUrl="https://api.example.com"
|
|
514
|
+
* pathname={usePathname()}
|
|
515
|
+
* navigate={(to) => router.push(to)}
|
|
516
|
+
* services={{ 'auth.login': login }}
|
|
517
|
+
* />
|
|
518
|
+
* ```
|
|
519
|
+
*
|
|
520
|
+
* baseUrl 可选:sources / pageEndpoint 只写相对路径时以此为基准补全。
|
|
521
|
+
*
|
|
522
|
+
* 内置:多源拉取合并、menus×pages 继承、MenuRegistry 路由解析、访问守卫
|
|
523
|
+
* (缺省匿名守卫:非 public 且无 user → navigate 到 auth.loginPath,
|
|
524
|
+
* 可经 guard prop 替换)、DSL 布局渲染
|
|
525
|
+
* (PageOutlet 页面出口 + SitemapMenu 选中态 / activeMenu 高亮)、
|
|
526
|
+
* 页面内联 / 懒加载(id@version 缓存)、session.context 服务桥
|
|
527
|
+
* (${data.session.*})、缺省动作(app.reload / service.call)。
|
|
528
|
+
*
|
|
529
|
+
* 布局常驻:切换导航(同布局名)时仅 PageOutlet 内页面随路由重建。
|
|
530
|
+
*/
|
|
531
|
+
interface SitemapAppProps {
|
|
532
|
+
/** sitemap 接口 URL 列表(多源合并,冲突后源覆盖前源);相对路径以 baseUrl 补全 */
|
|
533
|
+
sources: string[];
|
|
534
|
+
/** 接口基准地址:sources / pageEndpoint 中的相对路径以此为基准补全 */
|
|
535
|
+
baseUrl?: string;
|
|
536
|
+
/** 当前路径(宿主路由注入,如 Next usePathname);缺省用内置浏览器路由 */
|
|
537
|
+
pathname?: string;
|
|
538
|
+
/** 站内导航实现(如 Next router.push);http(s) 外链自动新标签打开;
|
|
539
|
+
* 缺省用内置浏览器路由(History API) */
|
|
540
|
+
navigate?: (to: string) => void;
|
|
541
|
+
/** 当前 query(DSL ${route.query.x} 可读);缺省自 location.search 解析 */
|
|
542
|
+
query?: Record<string, string>;
|
|
543
|
+
/** 懒加载页面端点,缺省 /api/pages/{id} */
|
|
544
|
+
pageEndpoint?: SitemapLoaderOptions['pageEndpoint'];
|
|
545
|
+
/** 业务服务(auth.login 等);session.context 由组件自动注册 */
|
|
546
|
+
services?: Record<string, ServiceHandler>;
|
|
547
|
+
/** 业务动作;框架内置 app.reload / service.call 默认值,同名覆盖 */
|
|
548
|
+
actions?: Record<string, ActionHandler>;
|
|
549
|
+
/** 业务组件(同名覆盖内建;PageOutlet / SitemapMenu 为布局保留名) */
|
|
550
|
+
components?: Record<string, unknown>;
|
|
551
|
+
/** HTTP 钩子:所有 HTTP 出口(sitemap 源 / 页面端点 / 页面运行时)的统一加工(跨域改写 / 拆包) */
|
|
552
|
+
httpAdapter?: PactorHttpHooks;
|
|
553
|
+
/** fetch 实现(缺省全局 fetch;SSR / 测试可注入) */
|
|
554
|
+
fetcher?: FetchSitemapOptions['fetcher'];
|
|
555
|
+
/** 访问守卫(缺省 defaultSitemapGuard:匿名访问非 public 页 → 重定向 auth.loginPath) */
|
|
556
|
+
guard?: SitemapGuard;
|
|
557
|
+
/** 会话服务名(缺省 session.context) */
|
|
558
|
+
sessionService?: string;
|
|
559
|
+
/** 加载中视图 */
|
|
560
|
+
loading?: ReactNode;
|
|
561
|
+
/** sitemap 加载失败视图 */
|
|
562
|
+
renderError?: (error: Error) => ReactNode;
|
|
563
|
+
/** 路由未命中视图 */
|
|
564
|
+
renderNotFound?: (path: string) => ReactNode;
|
|
565
|
+
}
|
|
566
|
+
declare function SitemapApp(props: SitemapAppProps): react.JSX.Element | null;
|
|
567
|
+
|
|
568
|
+
/** createHttpHooks 配置 */
|
|
569
|
+
interface CreateHttpHooksOptions {
|
|
570
|
+
/** 项目内代理前缀:传入后跨域绝对地址改写到此前缀(由宿主服务端
|
|
571
|
+
* 转发);缺省不改写——服务端已开通 CORS,浏览器直连 */
|
|
572
|
+
proxyPrefix?: string;
|
|
573
|
+
/** 公共头注入(Authorization / 租户头等),对象或函数(每次请求求值) */
|
|
574
|
+
headers?: Record<string, string> | (() => Record<string, string>);
|
|
575
|
+
/** 响应拆包:缺省按 { code, data, message } 包裹协议处理(拆出 data,
|
|
576
|
+
* 非 0 抛错);后端不包裹时传 false 关闭 */
|
|
577
|
+
envelope?: boolean;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* 默认 HTTP 钩子(常用协议开箱即用):
|
|
581
|
+
* - request:缺省不改写地址(假定服务端已开通 CORS,浏览器直连);
|
|
582
|
+
* 传 proxyPrefix 时跨域绝对地址(origin ≠ 页面源)改写到项目内
|
|
583
|
+
* 代理前缀(path + query 保留),由宿主服务端代理转发
|
|
584
|
+
* (Vite server.proxy / Next rewrites / nginx);可注入公共头
|
|
585
|
+
* - response:{ code, data, message } 包裹结构拆包为 data,非 0 抛错
|
|
586
|
+
* (DSL 动作按失败处理);非包裹结构原样透传
|
|
587
|
+
*
|
|
588
|
+
* 后端协议不同(包裹结构 / 错误码约定)时自行实现 PactorHttpHooks。
|
|
589
|
+
*/
|
|
590
|
+
declare function createHttpHooks(options?: CreateHttpHooksOptions): PactorHttpHooks;
|
|
591
|
+
/**
|
|
592
|
+
* 把 PactorHttpHooks 包装到 fetcher 上:sitemap 源 / 页面端点等框架自发
|
|
593
|
+
* 请求与页面运行时走同一套 HTTP 加工(跨域改写 / 鉴权头 / 响应拆包)。
|
|
594
|
+
* response 钩子仅作用于 2xx(错误响应原样返回,由调用方判定 HTTP 错误)。
|
|
595
|
+
*/
|
|
596
|
+
declare function withHttpHooks(fetcher: typeof fetch, hooks?: PactorHttpHooks): typeof fetch;
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* menus × pages 合并:type: 'page' 且带 pageId 的条目缺省从引用页面
|
|
600
|
+
* 继承 path / title(仅分叉时覆写);group / link 原样透传。
|
|
601
|
+
* 产物可直接 new MenuRegistry(...) 做路由匹配。
|
|
602
|
+
*/
|
|
603
|
+
declare function mergeSitemapMenus(sitemap: SitemapResource): SitemapMenuItem[];
|
|
604
|
+
/** ui Menu 组件 items 形态(可见菜单树 → 导航数据;key = 路径) */
|
|
605
|
+
interface SitemapNavItem {
|
|
606
|
+
key: string;
|
|
607
|
+
label: string;
|
|
608
|
+
icon?: string;
|
|
609
|
+
disabled?: boolean;
|
|
610
|
+
children?: SitemapNavItem[];
|
|
611
|
+
}
|
|
612
|
+
declare function toSitemapNavItems(menuTree: MenuItem[]): SitemapNavItem[];
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* 会话上下文(session.context 服务返回值):布局 / 页面 DSL 经
|
|
616
|
+
* service dataSource 消费(${data.session.*})。
|
|
617
|
+
* 框架原生 user / menus 作用域属设计目标(design/dynamic-page.md
|
|
618
|
+
* 落地影响 #3),当前经服务桥实现。
|
|
619
|
+
*/
|
|
620
|
+
interface SitemapSessionContext {
|
|
621
|
+
user?: Record<string, unknown>;
|
|
622
|
+
app: Record<string, unknown>;
|
|
623
|
+
menus: SitemapNavItem[];
|
|
624
|
+
}
|
|
625
|
+
/** 注册会话桥服务(缺省名 session.context,与 loader 注入的 dataSource 对应) */
|
|
626
|
+
declare function createSitemapSessionServices(session: SitemapSessionContext, serviceName?: string): Record<string, ServiceHandler>;
|
|
627
|
+
|
|
628
|
+
export { Application, type ApplicationProps, type AuthTokenProvider, type CreateHttpHooksOptions, DslPageLoader, type DslPageLoaderProps, type FetchSitemapOptions, type LayoutDsl, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, SitemapApp, type SitemapAppProps, type SitemapGuard, type SitemapGuardContext, type SitemapGuardDecision, type SitemapLoaderOptions, type SitemapMenuItem, type SitemapNavItem, type SitemapPageEntry, type SitemapResource, type SitemapRouteMatch, type SitemapRouteResolution, type SitemapSessionContext, createHttpHooks, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, createSitemapLoader, createSitemapSessionServices, defaultSitemapActions, defaultSitemapGuard, fetchSitemap, mergeSitemapMenus, resolveSitemapRoute, toSitemapNavItems, withHttpHooks, wrapHttpAdapter };
|