@pactor-app/app 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/index.cjs +260 -63
- package/dist/index.d.cts +108 -4
- package/dist/index.d.ts +108 -4
- package/dist/index.js +271 -67
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -67,6 +67,25 @@ app.mount('#root');
|
|
|
67
67
|
- 未命中路径渲染 404,命中但无权限渲染 403(菜单项 `permission` 配置);
|
|
68
68
|
- `overlay.open` 的 page 类型 overlay 经 loader 加载页面 DSL,子运行时共享应用级 registries。
|
|
69
69
|
|
|
70
|
+
## 嵌入式使用(PactorPage / createPactorPage)
|
|
71
|
+
|
|
72
|
+
存量项目(已有自己的路由,或 Next.js 等框架)中局部嵌入 DSL 页面,不接管路由:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { createPactorPage } from '@pactor-app/app';
|
|
76
|
+
import '@pactor-app/ui/styles.css';
|
|
77
|
+
|
|
78
|
+
// 工厂:组装一次(registries / 交互层 / i18n),多页面实例共享
|
|
79
|
+
const Page = createPactorPage({ loader, services, permissions: ['customer:view'] });
|
|
80
|
+
|
|
81
|
+
<Page pageId="customer-detail" route={{ params: { id } }} />
|
|
82
|
+
// 或直接传 PageDsl:<Page page={pageDsl} />
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- 交互层(confirm / message / overlay)与整应用模式一致;多实例状态互相隔离
|
|
86
|
+
- 跳转为自然导航:`Link` 组件渲染原生 `<a href>`,`navigate` 动作退化为 `location.assign`——不注入宿主路由对象
|
|
87
|
+
- `route.params` / `route.query` 经 props 纯数据注入(如 Next.js 的 `searchParams`)
|
|
88
|
+
|
|
70
89
|
## 文档
|
|
71
90
|
|
|
72
91
|
完整文档见 <https://github.com/426-330/pactor/tree/main/docs>(`pnpm docs:dev` 本地启动文档站)。
|
package/dist/index.cjs
CHANGED
|
@@ -22,21 +22,22 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
Application: () => Application,
|
|
24
24
|
DslPageLoader: () => DslPageLoader,
|
|
25
|
+
PactorPage: () => PactorPage,
|
|
25
26
|
PageErrorBoundary: () => PageErrorBoundary,
|
|
26
27
|
ReactRouterBinding: () => ReactRouterBinding,
|
|
27
|
-
createPactorApplication: () => createPactorApplication
|
|
28
|
+
createPactorApplication: () => createPactorApplication,
|
|
29
|
+
createPactorPage: () => createPactorPage,
|
|
30
|
+
createRuntimeHttpAdapter: () => createRuntimeHttpAdapter,
|
|
31
|
+
wrapHttpAdapter: () => wrapHttpAdapter
|
|
28
32
|
});
|
|
29
33
|
module.exports = __toCommonJS(index_exports);
|
|
30
34
|
|
|
31
35
|
// src/application.ts
|
|
32
|
-
var import_core2 = require("@pactor-app/core");
|
|
33
|
-
var import_components = require("@pactor-app/ui/components");
|
|
34
|
-
var import_interaction = require("@pactor-app/ui/interaction");
|
|
35
36
|
var import_layout2 = require("@pactor-app/ui/layout");
|
|
36
37
|
var import_permission = require("@pactor-app/permission");
|
|
37
38
|
var import_resource = require("@pactor-app/resource");
|
|
38
39
|
var import_router2 = require("@pactor-app/router");
|
|
39
|
-
var
|
|
40
|
+
var import_runtime4 = require("@pactor-app/runtime");
|
|
40
41
|
var import_react5 = require("react");
|
|
41
42
|
var import_client = require("react-dom/client");
|
|
42
43
|
|
|
@@ -374,6 +375,94 @@ function ForbiddenPage() {
|
|
|
374
375
|
);
|
|
375
376
|
}
|
|
376
377
|
|
|
378
|
+
// src/assembly.ts
|
|
379
|
+
var import_core2 = require("@pactor-app/core");
|
|
380
|
+
var import_components = require("@pactor-app/ui/components");
|
|
381
|
+
var import_interaction = require("@pactor-app/ui/interaction");
|
|
382
|
+
var import_runtime3 = require("@pactor-app/runtime");
|
|
383
|
+
function upsert(registry, name, item) {
|
|
384
|
+
if (registry.has(name)) {
|
|
385
|
+
registry.unregister(name);
|
|
386
|
+
}
|
|
387
|
+
registry.register(name, item);
|
|
388
|
+
}
|
|
389
|
+
function upsertAll(registry, entries) {
|
|
390
|
+
for (const [name, item] of Object.entries(entries ?? {})) {
|
|
391
|
+
upsert(registry, name, item);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
function createRuntimeHttpAdapter(authTokenProvider) {
|
|
395
|
+
const base = (0, import_runtime3.createFetchHttpAdapter)();
|
|
396
|
+
if (authTokenProvider === void 0) {
|
|
397
|
+
return base;
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
async request(config) {
|
|
401
|
+
const token = await authTokenProvider();
|
|
402
|
+
if (token === void 0 || token === "") {
|
|
403
|
+
return base.request(config);
|
|
404
|
+
}
|
|
405
|
+
return base.request({
|
|
406
|
+
...config,
|
|
407
|
+
headers: { ...config.headers, authorization: `Bearer ${token}` }
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
function wrapHttpAdapter(base, hooks) {
|
|
413
|
+
if (!hooks) {
|
|
414
|
+
return base;
|
|
415
|
+
}
|
|
416
|
+
return {
|
|
417
|
+
async request(config) {
|
|
418
|
+
const finalConfig = hooks.request ? await hooks.request(config) : config;
|
|
419
|
+
const data = await base.request(finalConfig);
|
|
420
|
+
return hooks.response ? hooks.response(data) : data;
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function createPactorAssembly(options) {
|
|
425
|
+
const overlayManager = new import_interaction.OverlayManager();
|
|
426
|
+
const uiBridge = (0, import_interaction.createUiBridge)();
|
|
427
|
+
const interactionKit = options.interactionKit ?? options.ui?.interactionKit ?? {
|
|
428
|
+
Provider: import_interaction.ShadcnInteractionProvider,
|
|
429
|
+
OverlayHost: import_interaction.ShadcnOverlayHost
|
|
430
|
+
};
|
|
431
|
+
const components = (options.componentRegistry ?? options.ui?.componentRegistry)?.() ?? (0, import_components.createShadcnComponentRegistry)();
|
|
432
|
+
upsertAll(components, options.components);
|
|
433
|
+
const actions = new import_core2.Registry("ActionRegistry");
|
|
434
|
+
(0, import_interaction.registerInteractionActions)(actions, overlayManager, uiBridge);
|
|
435
|
+
upsert(actions, "navigate", (action) => {
|
|
436
|
+
const to = action.params?.["to"];
|
|
437
|
+
if (typeof to !== "string" || to === "") {
|
|
438
|
+
return {
|
|
439
|
+
ok: false,
|
|
440
|
+
error: new Error("[@pactor-app/app] navigate \u52A8\u4F5C\u7F3A\u5C11 params.to\uFF08string\uFF09")
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
options.navigate(to);
|
|
444
|
+
return { ok: true };
|
|
445
|
+
});
|
|
446
|
+
upsertAll(actions, options.actions);
|
|
447
|
+
const services = new import_core2.Registry("ServiceRegistry");
|
|
448
|
+
upsertAll(services, options.services);
|
|
449
|
+
const capabilities = new import_core2.Registry("CapabilityRegistry");
|
|
450
|
+
upsertAll(capabilities, options.capabilities);
|
|
451
|
+
return {
|
|
452
|
+
components,
|
|
453
|
+
actions,
|
|
454
|
+
services,
|
|
455
|
+
capabilities,
|
|
456
|
+
overlayManager,
|
|
457
|
+
uiBridge,
|
|
458
|
+
interactionKit,
|
|
459
|
+
httpAdapter: wrapHttpAdapter(
|
|
460
|
+
createRuntimeHttpAdapter(options.authTokenProvider),
|
|
461
|
+
options.httpAdapter
|
|
462
|
+
)
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
377
466
|
// src/application.ts
|
|
378
467
|
var ReactRouterBinding = class {
|
|
379
468
|
constructor() {
|
|
@@ -419,17 +508,6 @@ var ReactRouterBinding = class {
|
|
|
419
508
|
function isRecord(value) {
|
|
420
509
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
421
510
|
}
|
|
422
|
-
function upsert(registry, name, item) {
|
|
423
|
-
if (registry.has(name)) {
|
|
424
|
-
registry.unregister(name);
|
|
425
|
-
}
|
|
426
|
-
registry.register(name, item);
|
|
427
|
-
}
|
|
428
|
-
function upsertAll(registry, entries) {
|
|
429
|
-
for (const [name, item] of Object.entries(entries ?? {})) {
|
|
430
|
-
upsert(registry, name, item);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
511
|
function createResourceHttpAdapter(authTokenProvider) {
|
|
434
512
|
const base = (0, import_resource.createFetchAdapter)();
|
|
435
513
|
if (authTokenProvider === void 0) {
|
|
@@ -446,24 +524,6 @@ function createResourceHttpAdapter(authTokenProvider) {
|
|
|
446
524
|
});
|
|
447
525
|
};
|
|
448
526
|
}
|
|
449
|
-
function createRuntimeHttpAdapter(authTokenProvider) {
|
|
450
|
-
const base = (0, import_runtime3.createFetchHttpAdapter)();
|
|
451
|
-
if (authTokenProvider === void 0) {
|
|
452
|
-
return base;
|
|
453
|
-
}
|
|
454
|
-
return {
|
|
455
|
-
async request(config) {
|
|
456
|
-
const token = await authTokenProvider();
|
|
457
|
-
if (token === void 0 || token === "") {
|
|
458
|
-
return base.request(config);
|
|
459
|
-
}
|
|
460
|
-
return base.request({
|
|
461
|
-
...config,
|
|
462
|
-
headers: { ...config.headers, authorization: `Bearer ${token}` }
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
527
|
var MENU_TYPES = /* @__PURE__ */ new Set(["group", "page", "link"]);
|
|
468
528
|
function sanitizeMenus(raw) {
|
|
469
529
|
if (!Array.isArray(raw)) {
|
|
@@ -520,42 +580,29 @@ function createPactorApplication(options) {
|
|
|
520
580
|
}
|
|
521
581
|
const { appId } = options;
|
|
522
582
|
const routerOptions = options.router ?? {};
|
|
523
|
-
const overlayManager = new import_interaction.OverlayManager();
|
|
524
|
-
const uiBridge = (0, import_interaction.createUiBridge)();
|
|
525
583
|
const permissionStore = new import_permission.PermissionStore();
|
|
526
584
|
const layoutRegistry = (options.layoutRegistry ?? options.ui?.layoutRegistry)?.() ?? (0, import_layout2.createShadcnLayoutRegistry)();
|
|
527
|
-
const interactionKit = options.interactionKit ?? options.ui?.interactionKit ?? {
|
|
528
|
-
Provider: import_interaction.ShadcnInteractionProvider,
|
|
529
|
-
OverlayHost: import_interaction.ShadcnOverlayHost
|
|
530
|
-
};
|
|
531
585
|
const navigation = new ReactRouterBinding();
|
|
586
|
+
const assembly = createPactorAssembly({
|
|
587
|
+
componentRegistry: options.componentRegistry,
|
|
588
|
+
ui: options.ui,
|
|
589
|
+
interactionKit: options.interactionKit,
|
|
590
|
+
components: options.components,
|
|
591
|
+
actions: options.actions,
|
|
592
|
+
services: options.services,
|
|
593
|
+
capabilities: options.capabilities,
|
|
594
|
+
authTokenProvider: options.authTokenProvider,
|
|
595
|
+
httpAdapter: options.httpAdapter,
|
|
596
|
+
navigate: (to) => navigation.push(to)
|
|
597
|
+
});
|
|
598
|
+
const { components, actions, services, capabilities, httpAdapter } = assembly;
|
|
599
|
+
const { overlayManager, uiBridge, interactionKit } = assembly;
|
|
532
600
|
const loader = options.loader ?? new import_resource.HttpDslResourceLoader({
|
|
533
601
|
baseUrl: options.api?.baseURL,
|
|
534
602
|
adapter: createResourceHttpAdapter(options.authTokenProvider)
|
|
535
603
|
});
|
|
536
|
-
const httpAdapter = createRuntimeHttpAdapter(options.authTokenProvider);
|
|
537
604
|
const permissionAdapter = (0, import_permission.createPermissionAdapter)(permissionStore);
|
|
538
605
|
const routerAdapter = (0, import_router2.createRouterAdapter)(navigation);
|
|
539
|
-
const components = (options.componentRegistry ?? options.ui?.componentRegistry)?.() ?? (0, import_components.createShadcnComponentRegistry)();
|
|
540
|
-
upsertAll(components, options.components);
|
|
541
|
-
const actions = new import_core2.Registry("ActionRegistry");
|
|
542
|
-
(0, import_interaction.registerInteractionActions)(actions, overlayManager, uiBridge);
|
|
543
|
-
upsert(actions, "navigate", (action) => {
|
|
544
|
-
const to = action.params?.["to"];
|
|
545
|
-
if (typeof to !== "string" || to === "") {
|
|
546
|
-
return {
|
|
547
|
-
ok: false,
|
|
548
|
-
error: new Error("[@pactor-app/app] navigate \u52A8\u4F5C\u7F3A\u5C11 params.to\uFF08string\uFF09")
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
navigation.push(to);
|
|
552
|
-
return { ok: true };
|
|
553
|
-
});
|
|
554
|
-
upsertAll(actions, options.actions);
|
|
555
|
-
const services = new import_core2.Registry("ServiceRegistry");
|
|
556
|
-
upsertAll(services, options.services);
|
|
557
|
-
const capabilities = new import_core2.Registry("CapabilityRegistry");
|
|
558
|
-
upsertAll(capabilities, options.capabilities);
|
|
559
606
|
let session = null;
|
|
560
607
|
const handle = {
|
|
561
608
|
appId,
|
|
@@ -606,7 +653,7 @@ function createPactorApplication(options) {
|
|
|
606
653
|
return next;
|
|
607
654
|
},
|
|
608
655
|
createPageRuntime(pageDsl, route) {
|
|
609
|
-
return (0,
|
|
656
|
+
return (0, import_runtime4.createPageRuntime)(pageDsl, {
|
|
610
657
|
components,
|
|
611
658
|
actions,
|
|
612
659
|
services,
|
|
@@ -670,11 +717,161 @@ function createPactorApplication(options) {
|
|
|
670
717
|
}
|
|
671
718
|
};
|
|
672
719
|
}
|
|
720
|
+
|
|
721
|
+
// src/embedded.tsx
|
|
722
|
+
var import_core3 = require("@pactor-app/core");
|
|
723
|
+
var import_permission2 = require("@pactor-app/permission");
|
|
724
|
+
var import_runtime5 = require("@pactor-app/runtime");
|
|
725
|
+
var import_react6 = require("react");
|
|
726
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
727
|
+
function createPactorPage(options = {}) {
|
|
728
|
+
const assembly = createPactorAssembly({
|
|
729
|
+
...options,
|
|
730
|
+
// 嵌入模式:navigate 退化为自然跳转(设计决策 D2,不注入宿主路由对象)
|
|
731
|
+
navigate: (to) => {
|
|
732
|
+
if (typeof window !== "undefined") {
|
|
733
|
+
window.location.assign(to);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
let permission;
|
|
738
|
+
if (options.permission !== void 0) {
|
|
739
|
+
permission = options.permission;
|
|
740
|
+
} else if (options.permissions !== void 0) {
|
|
741
|
+
const store = new import_permission2.PermissionStore();
|
|
742
|
+
store.setPermissions(options.permissions);
|
|
743
|
+
permission = (0, import_permission2.createPermissionAdapter)(store);
|
|
744
|
+
} else {
|
|
745
|
+
permission = (0, import_runtime5.createDefaultPermissionAdapter)();
|
|
746
|
+
}
|
|
747
|
+
const i18n = (0, import_core3.createI18nContext)({
|
|
748
|
+
locale: options.locale,
|
|
749
|
+
defaultLocale: options.defaultLocale,
|
|
750
|
+
messages: options.messages
|
|
751
|
+
});
|
|
752
|
+
function createRuntime(pageDsl, route) {
|
|
753
|
+
return (0, import_runtime5.createPageRuntime)(pageDsl, {
|
|
754
|
+
components: assembly.components,
|
|
755
|
+
actions: assembly.actions,
|
|
756
|
+
services: assembly.services,
|
|
757
|
+
capabilities: assembly.capabilities,
|
|
758
|
+
permission,
|
|
759
|
+
http: assembly.httpAdapter,
|
|
760
|
+
route: { params: route?.params ?? {}, query: route?.query ?? {} },
|
|
761
|
+
locale: options.locale ?? "zh-CN",
|
|
762
|
+
defaultLocale: options.defaultLocale ?? "zh-CN",
|
|
763
|
+
messages: options.messages ?? {}
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
return function ConfiguredPactorPage(props) {
|
|
767
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EmbeddedPage, { assembly, options, i18n, createRuntime, resolvePage: options.loader ? resolvePage : void 0, ...props });
|
|
768
|
+
};
|
|
769
|
+
async function resolvePage(pageId) {
|
|
770
|
+
if (!options.loader) {
|
|
771
|
+
throw new Error("[@pactor-app/app] PactorPage: \u6309 pageId \u52A0\u8F7D\u9700\u8981 options.loader");
|
|
772
|
+
}
|
|
773
|
+
const resource = await options.loader.loadPage(pageId);
|
|
774
|
+
return resource.schema;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
function PactorPage(props) {
|
|
778
|
+
const { pageId, pageDsl, route, ...options } = props;
|
|
779
|
+
const factoryRef = (0, import_react6.useRef)(null);
|
|
780
|
+
if (factoryRef.current === null) {
|
|
781
|
+
factoryRef.current = createPactorPage(options);
|
|
782
|
+
}
|
|
783
|
+
const ConfiguredPage = factoryRef.current;
|
|
784
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ConfiguredPage, { pageId, pageDsl, route });
|
|
785
|
+
}
|
|
786
|
+
function EmbeddedPage({
|
|
787
|
+
assembly,
|
|
788
|
+
options,
|
|
789
|
+
i18n,
|
|
790
|
+
createRuntime,
|
|
791
|
+
resolvePage,
|
|
792
|
+
pageId,
|
|
793
|
+
pageDsl,
|
|
794
|
+
route
|
|
795
|
+
}) {
|
|
796
|
+
const [state, setState] = (0, import_react6.useState)({ status: "loading" });
|
|
797
|
+
const [retryTick, setRetryTick] = (0, import_react6.useState)(0);
|
|
798
|
+
const onError = options.onError;
|
|
799
|
+
(0, import_react6.useEffect)(() => {
|
|
800
|
+
let cancelled = false;
|
|
801
|
+
let runtime = null;
|
|
802
|
+
void (async () => {
|
|
803
|
+
try {
|
|
804
|
+
let resolved = pageDsl;
|
|
805
|
+
if (resolved === void 0) {
|
|
806
|
+
if (pageId === void 0) {
|
|
807
|
+
throw new Error("[@pactor-app/app] PactorPage: pageId \u4E0E pageDsl \u5FC5\u4F20\u5176\u4E00");
|
|
808
|
+
}
|
|
809
|
+
if (resolvePage === void 0) {
|
|
810
|
+
throw new Error("[@pactor-app/app] PactorPage: \u6309 pageId \u52A0\u8F7D\u9700\u8981 options.loader");
|
|
811
|
+
}
|
|
812
|
+
resolved = await resolvePage(pageId);
|
|
813
|
+
} else if ((0, import_core3.isDslSourceRef)(resolved)) {
|
|
814
|
+
const resolver = new import_runtime5.DslSourceResolver({
|
|
815
|
+
services: assembly.services,
|
|
816
|
+
http: assembly.httpAdapter,
|
|
817
|
+
getScope: () => ({
|
|
818
|
+
route: { params: route?.params ?? {}, query: route?.query ?? {} }
|
|
819
|
+
})
|
|
820
|
+
});
|
|
821
|
+
resolved = await resolver.resolve(resolved);
|
|
822
|
+
}
|
|
823
|
+
if (cancelled) {
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
runtime = createRuntime(resolved, route);
|
|
827
|
+
setState({ status: "ready", runtime });
|
|
828
|
+
void runtime.ready();
|
|
829
|
+
void runtime.show();
|
|
830
|
+
} catch (cause) {
|
|
831
|
+
if (!cancelled) {
|
|
832
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
833
|
+
onError?.(error);
|
|
834
|
+
setState({ status: "error", error });
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
})();
|
|
838
|
+
return () => {
|
|
839
|
+
cancelled = true;
|
|
840
|
+
if (runtime !== null && !runtime.destroyed) {
|
|
841
|
+
void runtime.hide();
|
|
842
|
+
void runtime.destroy();
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
}, [pageId, pageDsl, retryTick]);
|
|
846
|
+
const InteractionProvider = assembly.interactionKit.Provider;
|
|
847
|
+
const OverlayHost = assembly.interactionKit.OverlayHost;
|
|
848
|
+
let content;
|
|
849
|
+
if (state.status === "loading") {
|
|
850
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "pactor-app-page-loading", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(BootstrapSpinner, { style: { minHeight: 0, padding: 48 } }) });
|
|
851
|
+
} else if (state.status === "error") {
|
|
852
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
853
|
+
ResultView,
|
|
854
|
+
{
|
|
855
|
+
className: "pactor-app-page-load-error",
|
|
856
|
+
title: "\u9875\u9762\u52A0\u8F7D\u5931\u8D25",
|
|
857
|
+
subTitle: state.error.message,
|
|
858
|
+
extra: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: "\u91CD\u8BD5" })
|
|
859
|
+
}
|
|
860
|
+
);
|
|
861
|
+
} else {
|
|
862
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_runtime5.PageRuntimeView, { runtime: state.runtime, children: resolvePage !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OverlayHost, { manager: assembly.overlayManager, resolvePage }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OverlayHost, { manager: assembly.overlayManager }) }) });
|
|
863
|
+
}
|
|
864
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_runtime5.I18nContextProvider, { value: i18n, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InteractionProvider, { bridge: assembly.uiBridge, children: content }) });
|
|
865
|
+
}
|
|
673
866
|
// Annotate the CommonJS export names for ESM import in node:
|
|
674
867
|
0 && (module.exports = {
|
|
675
868
|
Application,
|
|
676
869
|
DslPageLoader,
|
|
870
|
+
PactorPage,
|
|
677
871
|
PageErrorBoundary,
|
|
678
872
|
ReactRouterBinding,
|
|
679
|
-
createPactorApplication
|
|
873
|
+
createPactorApplication,
|
|
874
|
+
createPactorPage,
|
|
875
|
+
createRuntimeHttpAdapter,
|
|
876
|
+
wrapHttpAdapter
|
|
680
877
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,13 +1,61 @@
|
|
|
1
|
-
import { I18nMessages, PageDsl,
|
|
2
|
-
import {
|
|
1
|
+
import { Registry, I18nMessages, PageDsl, DslSourceRef } from '@pactor-app/core';
|
|
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
6
|
import { NavigationBridge, NavigationLocation, NavigationListener, MenuRegistry, RouteContext } from '@pactor-app/router';
|
|
7
|
-
import {
|
|
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';
|
|
10
10
|
|
|
11
|
+
/** 创建页面运行时 HTTP 出口适配器:注入 Authorization 头 */
|
|
12
|
+
declare function createRuntimeHttpAdapter(authTokenProvider: AuthTokenProvider | undefined): HttpAdapter;
|
|
13
|
+
/**
|
|
14
|
+
* HTTP 钩子(组装层):对页面运行时所有 HTTP 出口做统一加工。
|
|
15
|
+
* - `request`:发出前加工请求配置(如注入 token、改写 URL、追加公共 headers)
|
|
16
|
+
* - `response`:收到后加工返回数据(如把后端包裹结构 `{ code, data }`
|
|
17
|
+
* 归一化为 Pactor 需要的内容)
|
|
18
|
+
* 两个钩子均可异步;缺省时直通。
|
|
19
|
+
*/
|
|
20
|
+
interface PactorHttpHooks {
|
|
21
|
+
request?: (config: HttpRequestConfig) => HttpRequestConfig | Promise<HttpRequestConfig>;
|
|
22
|
+
response?: (data: unknown) => unknown | Promise<unknown>;
|
|
23
|
+
}
|
|
24
|
+
/** 把 PactorHttpHooks 包装到 HttpAdapter 上(无钩子则原样返回) */
|
|
25
|
+
declare function wrapHttpAdapter(base: HttpAdapter, hooks: PactorHttpHooks | undefined): HttpAdapter;
|
|
26
|
+
/**
|
|
27
|
+
* 组装内核选项(spec: embedded-page-view / application-bootstrap):
|
|
28
|
+
* 整应用模式与嵌入模式共享的装配输入。
|
|
29
|
+
*/
|
|
30
|
+
interface PactorAssemblyOptions {
|
|
31
|
+
/** 组件注册表工厂(槽位合并:显式选项 > ui 预设 > shadcn 默认) */
|
|
32
|
+
componentRegistry?: () => Registry<unknown>;
|
|
33
|
+
/** UI kit 预设(三槽位) */
|
|
34
|
+
ui?: UiKit;
|
|
35
|
+
/** 交互层组件对(缺省 shadcn 版) */
|
|
36
|
+
interactionKit?: {
|
|
37
|
+
Provider: ComponentType<InteractionProviderProps>;
|
|
38
|
+
OverlayHost: ComponentType<OverlayHostProps>;
|
|
39
|
+
};
|
|
40
|
+
/** 业务组件扩展(同名覆盖内置) */
|
|
41
|
+
components?: Record<string, unknown>;
|
|
42
|
+
/** 业务动作扩展(同名覆盖内置/交互动作) */
|
|
43
|
+
actions?: Record<string, ActionHandler>;
|
|
44
|
+
/** 业务服务扩展 */
|
|
45
|
+
services?: Record<string, ServiceHandler>;
|
|
46
|
+
/** 业务能力扩展 */
|
|
47
|
+
capabilities?: Record<string, unknown>;
|
|
48
|
+
/** 认证令牌:注入页面 HTTP 出口 */
|
|
49
|
+
authTokenProvider?: AuthTokenProvider;
|
|
50
|
+
/** HTTP 钩子:加工页面运行时所有 HTTP 出口(request 改配置 / response 改数据) */
|
|
51
|
+
httpAdapter?: PactorHttpHooks;
|
|
52
|
+
/**
|
|
53
|
+
* DSL `navigate` 动作的跳转实现(两种形态的差异点):
|
|
54
|
+
* 整应用模式 = 导航桥 push(react-router);嵌入模式 = location.assign
|
|
55
|
+
*/
|
|
56
|
+
navigate: (to: string) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
11
59
|
/** 认证令牌提供者:同步或异步返回 Bearer token(无令牌返回 undefined) */
|
|
12
60
|
type AuthTokenProvider = () => string | undefined | Promise<string | undefined>;
|
|
13
61
|
/** 路由配置(V1 支持 browser + basename;hash 预留) */
|
|
@@ -89,6 +137,8 @@ interface PactorApplicationOptions {
|
|
|
89
137
|
headerExtra?: ReactNode;
|
|
90
138
|
/** 认证令牌:注入 DSL 资源请求与页面 HTTP 出口(Authorization: Bearer) */
|
|
91
139
|
authTokenProvider?: AuthTokenProvider;
|
|
140
|
+
/** HTTP 钩子:加工页面运行时所有 HTTP 出口(request 改配置 / response 改数据) */
|
|
141
|
+
httpAdapter?: PactorHttpHooks;
|
|
92
142
|
/** 当前语言代码(优先级高于 bootstrap.locale 与浏览器语言) */
|
|
93
143
|
locale?: string;
|
|
94
144
|
/** 回退语言代码(缺省 'zh-CN') */
|
|
@@ -275,4 +325,58 @@ declare class PageErrorBoundary extends Component<PageErrorBoundaryProps, PageEr
|
|
|
275
325
|
render(): ReactNode;
|
|
276
326
|
}
|
|
277
327
|
|
|
278
|
-
|
|
328
|
+
/**
|
|
329
|
+
* 嵌入式页面 props(spec: embedded-page-view):
|
|
330
|
+
* `pageId`(经 loader 加载)与 `pageDsl`(直接传入或动态引用)二选一。
|
|
331
|
+
*/
|
|
332
|
+
interface PactorPageProps {
|
|
333
|
+
/** 页面 id(经 options.loader 加载) */
|
|
334
|
+
pageId?: string;
|
|
335
|
+
/**
|
|
336
|
+
* 直接传入的 PageDsl(不经 loader),或 DslSourceRef 动态引用——
|
|
337
|
+
* 经 service/http 通道远端加载 PageDsl,校验通过后创建运行时;
|
|
338
|
+
* 加载失败走错误态与 onError,重试重新请求
|
|
339
|
+
*/
|
|
340
|
+
pageDsl?: PageDsl | DslSourceRef;
|
|
341
|
+
/** 路由作用域注入:DSL 内 `${route.params.x}` / `${route.query.x}` 可读 */
|
|
342
|
+
route?: {
|
|
343
|
+
params?: Record<string, unknown>;
|
|
344
|
+
query?: Record<string, unknown>;
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* 嵌入式页面工厂选项(设计决策 D1/D2):整应用模式的组装选项子集
|
|
349
|
+
* (无路由、无外壳布局);route 上下文经 props 纯数据注入。
|
|
350
|
+
*/
|
|
351
|
+
interface PactorPageOptions extends Omit<PactorAssemblyOptions, 'navigate'> {
|
|
352
|
+
/** 资源加载器(按 pageId 加载页面时需要) */
|
|
353
|
+
loader?: DslResourceLoader;
|
|
354
|
+
/** 权限码列表(缺省全部放行;细粒度控制可传 permission 适配器) */
|
|
355
|
+
permissions?: string[];
|
|
356
|
+
/** 权限适配器(优先于 permissions) */
|
|
357
|
+
permission?: PermissionAdapter;
|
|
358
|
+
/** 认证令牌(注入页面 HTTP 出口) */
|
|
359
|
+
authTokenProvider?: AuthTokenProvider;
|
|
360
|
+
/** 当前语言代码(缺省 'zh-CN') */
|
|
361
|
+
locale?: string;
|
|
362
|
+
/** 回退语言代码(缺省 'zh-CN') */
|
|
363
|
+
defaultLocale?: string;
|
|
364
|
+
/** 翻译消息表 */
|
|
365
|
+
messages?: I18nMessages;
|
|
366
|
+
/** 页面加载/校验失败回调 */
|
|
367
|
+
onError?: (error: Error) => void;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* 嵌入式页面工厂(spec: embedded-page-view):返回预配置的 PactorPage 组件。
|
|
371
|
+
* 组装一次(registries / 交互层 / i18n),每个组件实例自持独立
|
|
372
|
+
* PageRuntime(多实例隔离)。
|
|
373
|
+
*/
|
|
374
|
+
declare function createPactorPage(options?: PactorPageOptions): ComponentType<PactorPageProps>;
|
|
375
|
+
/**
|
|
376
|
+
* PactorPage 组件(spec: embedded-page-view):嵌入式 DSL 页面。
|
|
377
|
+
* 直接使用时把工厂选项一并作为 props 传入(首次渲染时组装一次);
|
|
378
|
+
* 需要复用同一组装配时优先用 `createPactorPage(options)` 工厂。
|
|
379
|
+
*/
|
|
380
|
+
declare function PactorPage(props: PactorPageProps & PactorPageOptions): react.JSX.Element;
|
|
381
|
+
|
|
382
|
+
export { Application, type ApplicationProps, type AuthTokenProvider, DslPageLoader, type DslPageLoaderProps, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, type UiKit, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, wrapHttpAdapter };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,61 @@
|
|
|
1
|
-
import { I18nMessages, PageDsl,
|
|
2
|
-
import {
|
|
1
|
+
import { Registry, I18nMessages, PageDsl, DslSourceRef } from '@pactor-app/core';
|
|
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
6
|
import { NavigationBridge, NavigationLocation, NavigationListener, MenuRegistry, RouteContext } from '@pactor-app/router';
|
|
7
|
-
import {
|
|
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';
|
|
10
10
|
|
|
11
|
+
/** 创建页面运行时 HTTP 出口适配器:注入 Authorization 头 */
|
|
12
|
+
declare function createRuntimeHttpAdapter(authTokenProvider: AuthTokenProvider | undefined): HttpAdapter;
|
|
13
|
+
/**
|
|
14
|
+
* HTTP 钩子(组装层):对页面运行时所有 HTTP 出口做统一加工。
|
|
15
|
+
* - `request`:发出前加工请求配置(如注入 token、改写 URL、追加公共 headers)
|
|
16
|
+
* - `response`:收到后加工返回数据(如把后端包裹结构 `{ code, data }`
|
|
17
|
+
* 归一化为 Pactor 需要的内容)
|
|
18
|
+
* 两个钩子均可异步;缺省时直通。
|
|
19
|
+
*/
|
|
20
|
+
interface PactorHttpHooks {
|
|
21
|
+
request?: (config: HttpRequestConfig) => HttpRequestConfig | Promise<HttpRequestConfig>;
|
|
22
|
+
response?: (data: unknown) => unknown | Promise<unknown>;
|
|
23
|
+
}
|
|
24
|
+
/** 把 PactorHttpHooks 包装到 HttpAdapter 上(无钩子则原样返回) */
|
|
25
|
+
declare function wrapHttpAdapter(base: HttpAdapter, hooks: PactorHttpHooks | undefined): HttpAdapter;
|
|
26
|
+
/**
|
|
27
|
+
* 组装内核选项(spec: embedded-page-view / application-bootstrap):
|
|
28
|
+
* 整应用模式与嵌入模式共享的装配输入。
|
|
29
|
+
*/
|
|
30
|
+
interface PactorAssemblyOptions {
|
|
31
|
+
/** 组件注册表工厂(槽位合并:显式选项 > ui 预设 > shadcn 默认) */
|
|
32
|
+
componentRegistry?: () => Registry<unknown>;
|
|
33
|
+
/** UI kit 预设(三槽位) */
|
|
34
|
+
ui?: UiKit;
|
|
35
|
+
/** 交互层组件对(缺省 shadcn 版) */
|
|
36
|
+
interactionKit?: {
|
|
37
|
+
Provider: ComponentType<InteractionProviderProps>;
|
|
38
|
+
OverlayHost: ComponentType<OverlayHostProps>;
|
|
39
|
+
};
|
|
40
|
+
/** 业务组件扩展(同名覆盖内置) */
|
|
41
|
+
components?: Record<string, unknown>;
|
|
42
|
+
/** 业务动作扩展(同名覆盖内置/交互动作) */
|
|
43
|
+
actions?: Record<string, ActionHandler>;
|
|
44
|
+
/** 业务服务扩展 */
|
|
45
|
+
services?: Record<string, ServiceHandler>;
|
|
46
|
+
/** 业务能力扩展 */
|
|
47
|
+
capabilities?: Record<string, unknown>;
|
|
48
|
+
/** 认证令牌:注入页面 HTTP 出口 */
|
|
49
|
+
authTokenProvider?: AuthTokenProvider;
|
|
50
|
+
/** HTTP 钩子:加工页面运行时所有 HTTP 出口(request 改配置 / response 改数据) */
|
|
51
|
+
httpAdapter?: PactorHttpHooks;
|
|
52
|
+
/**
|
|
53
|
+
* DSL `navigate` 动作的跳转实现(两种形态的差异点):
|
|
54
|
+
* 整应用模式 = 导航桥 push(react-router);嵌入模式 = location.assign
|
|
55
|
+
*/
|
|
56
|
+
navigate: (to: string) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
11
59
|
/** 认证令牌提供者:同步或异步返回 Bearer token(无令牌返回 undefined) */
|
|
12
60
|
type AuthTokenProvider = () => string | undefined | Promise<string | undefined>;
|
|
13
61
|
/** 路由配置(V1 支持 browser + basename;hash 预留) */
|
|
@@ -89,6 +137,8 @@ interface PactorApplicationOptions {
|
|
|
89
137
|
headerExtra?: ReactNode;
|
|
90
138
|
/** 认证令牌:注入 DSL 资源请求与页面 HTTP 出口(Authorization: Bearer) */
|
|
91
139
|
authTokenProvider?: AuthTokenProvider;
|
|
140
|
+
/** HTTP 钩子:加工页面运行时所有 HTTP 出口(request 改配置 / response 改数据) */
|
|
141
|
+
httpAdapter?: PactorHttpHooks;
|
|
92
142
|
/** 当前语言代码(优先级高于 bootstrap.locale 与浏览器语言) */
|
|
93
143
|
locale?: string;
|
|
94
144
|
/** 回退语言代码(缺省 'zh-CN') */
|
|
@@ -275,4 +325,58 @@ declare class PageErrorBoundary extends Component<PageErrorBoundaryProps, PageEr
|
|
|
275
325
|
render(): ReactNode;
|
|
276
326
|
}
|
|
277
327
|
|
|
278
|
-
|
|
328
|
+
/**
|
|
329
|
+
* 嵌入式页面 props(spec: embedded-page-view):
|
|
330
|
+
* `pageId`(经 loader 加载)与 `pageDsl`(直接传入或动态引用)二选一。
|
|
331
|
+
*/
|
|
332
|
+
interface PactorPageProps {
|
|
333
|
+
/** 页面 id(经 options.loader 加载) */
|
|
334
|
+
pageId?: string;
|
|
335
|
+
/**
|
|
336
|
+
* 直接传入的 PageDsl(不经 loader),或 DslSourceRef 动态引用——
|
|
337
|
+
* 经 service/http 通道远端加载 PageDsl,校验通过后创建运行时;
|
|
338
|
+
* 加载失败走错误态与 onError,重试重新请求
|
|
339
|
+
*/
|
|
340
|
+
pageDsl?: PageDsl | DslSourceRef;
|
|
341
|
+
/** 路由作用域注入:DSL 内 `${route.params.x}` / `${route.query.x}` 可读 */
|
|
342
|
+
route?: {
|
|
343
|
+
params?: Record<string, unknown>;
|
|
344
|
+
query?: Record<string, unknown>;
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* 嵌入式页面工厂选项(设计决策 D1/D2):整应用模式的组装选项子集
|
|
349
|
+
* (无路由、无外壳布局);route 上下文经 props 纯数据注入。
|
|
350
|
+
*/
|
|
351
|
+
interface PactorPageOptions extends Omit<PactorAssemblyOptions, 'navigate'> {
|
|
352
|
+
/** 资源加载器(按 pageId 加载页面时需要) */
|
|
353
|
+
loader?: DslResourceLoader;
|
|
354
|
+
/** 权限码列表(缺省全部放行;细粒度控制可传 permission 适配器) */
|
|
355
|
+
permissions?: string[];
|
|
356
|
+
/** 权限适配器(优先于 permissions) */
|
|
357
|
+
permission?: PermissionAdapter;
|
|
358
|
+
/** 认证令牌(注入页面 HTTP 出口) */
|
|
359
|
+
authTokenProvider?: AuthTokenProvider;
|
|
360
|
+
/** 当前语言代码(缺省 'zh-CN') */
|
|
361
|
+
locale?: string;
|
|
362
|
+
/** 回退语言代码(缺省 'zh-CN') */
|
|
363
|
+
defaultLocale?: string;
|
|
364
|
+
/** 翻译消息表 */
|
|
365
|
+
messages?: I18nMessages;
|
|
366
|
+
/** 页面加载/校验失败回调 */
|
|
367
|
+
onError?: (error: Error) => void;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* 嵌入式页面工厂(spec: embedded-page-view):返回预配置的 PactorPage 组件。
|
|
371
|
+
* 组装一次(registries / 交互层 / i18n),每个组件实例自持独立
|
|
372
|
+
* PageRuntime(多实例隔离)。
|
|
373
|
+
*/
|
|
374
|
+
declare function createPactorPage(options?: PactorPageOptions): ComponentType<PactorPageProps>;
|
|
375
|
+
/**
|
|
376
|
+
* PactorPage 组件(spec: embedded-page-view):嵌入式 DSL 页面。
|
|
377
|
+
* 直接使用时把工厂选项一并作为 props 传入(首次渲染时组装一次);
|
|
378
|
+
* 需要复用同一组装配时优先用 `createPactorPage(options)` 工厂。
|
|
379
|
+
*/
|
|
380
|
+
declare function PactorPage(props: PactorPageProps & PactorPageOptions): react.JSX.Element;
|
|
381
|
+
|
|
382
|
+
export { Application, type ApplicationProps, type AuthTokenProvider, DslPageLoader, type DslPageLoaderProps, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, type UiKit, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, wrapHttpAdapter };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
// src/application.ts
|
|
2
|
-
import { Registry } from "@pactor-app/core";
|
|
3
|
-
import { createShadcnComponentRegistry } from "@pactor-app/ui/components";
|
|
4
|
-
import {
|
|
5
|
-
createUiBridge,
|
|
6
|
-
OverlayManager,
|
|
7
|
-
registerInteractionActions,
|
|
8
|
-
ShadcnInteractionProvider,
|
|
9
|
-
ShadcnOverlayHost
|
|
10
|
-
} from "@pactor-app/ui/interaction";
|
|
11
2
|
import {
|
|
12
3
|
createShadcnLayoutRegistry
|
|
13
4
|
} from "@pactor-app/ui/layout";
|
|
@@ -21,7 +12,6 @@ import {
|
|
|
21
12
|
MenuRegistry
|
|
22
13
|
} from "@pactor-app/router";
|
|
23
14
|
import {
|
|
24
|
-
createFetchHttpAdapter,
|
|
25
15
|
createPageRuntime
|
|
26
16
|
} from "@pactor-app/runtime";
|
|
27
17
|
import { createElement } from "react";
|
|
@@ -367,6 +357,102 @@ function ForbiddenPage() {
|
|
|
367
357
|
);
|
|
368
358
|
}
|
|
369
359
|
|
|
360
|
+
// src/assembly.ts
|
|
361
|
+
import { Registry } from "@pactor-app/core";
|
|
362
|
+
import { createShadcnComponentRegistry } from "@pactor-app/ui/components";
|
|
363
|
+
import {
|
|
364
|
+
createUiBridge,
|
|
365
|
+
OverlayManager,
|
|
366
|
+
registerInteractionActions,
|
|
367
|
+
ShadcnInteractionProvider,
|
|
368
|
+
ShadcnOverlayHost
|
|
369
|
+
} from "@pactor-app/ui/interaction";
|
|
370
|
+
import {
|
|
371
|
+
createFetchHttpAdapter
|
|
372
|
+
} from "@pactor-app/runtime";
|
|
373
|
+
function upsert(registry, name, item) {
|
|
374
|
+
if (registry.has(name)) {
|
|
375
|
+
registry.unregister(name);
|
|
376
|
+
}
|
|
377
|
+
registry.register(name, item);
|
|
378
|
+
}
|
|
379
|
+
function upsertAll(registry, entries) {
|
|
380
|
+
for (const [name, item] of Object.entries(entries ?? {})) {
|
|
381
|
+
upsert(registry, name, item);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
function createRuntimeHttpAdapter(authTokenProvider) {
|
|
385
|
+
const base = createFetchHttpAdapter();
|
|
386
|
+
if (authTokenProvider === void 0) {
|
|
387
|
+
return base;
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
async request(config) {
|
|
391
|
+
const token = await authTokenProvider();
|
|
392
|
+
if (token === void 0 || token === "") {
|
|
393
|
+
return base.request(config);
|
|
394
|
+
}
|
|
395
|
+
return base.request({
|
|
396
|
+
...config,
|
|
397
|
+
headers: { ...config.headers, authorization: `Bearer ${token}` }
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
function wrapHttpAdapter(base, hooks) {
|
|
403
|
+
if (!hooks) {
|
|
404
|
+
return base;
|
|
405
|
+
}
|
|
406
|
+
return {
|
|
407
|
+
async request(config) {
|
|
408
|
+
const finalConfig = hooks.request ? await hooks.request(config) : config;
|
|
409
|
+
const data = await base.request(finalConfig);
|
|
410
|
+
return hooks.response ? hooks.response(data) : data;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function createPactorAssembly(options) {
|
|
415
|
+
const overlayManager = new OverlayManager();
|
|
416
|
+
const uiBridge = createUiBridge();
|
|
417
|
+
const interactionKit = options.interactionKit ?? options.ui?.interactionKit ?? {
|
|
418
|
+
Provider: ShadcnInteractionProvider,
|
|
419
|
+
OverlayHost: ShadcnOverlayHost
|
|
420
|
+
};
|
|
421
|
+
const components = (options.componentRegistry ?? options.ui?.componentRegistry)?.() ?? createShadcnComponentRegistry();
|
|
422
|
+
upsertAll(components, options.components);
|
|
423
|
+
const actions = new Registry("ActionRegistry");
|
|
424
|
+
registerInteractionActions(actions, overlayManager, uiBridge);
|
|
425
|
+
upsert(actions, "navigate", (action) => {
|
|
426
|
+
const to = action.params?.["to"];
|
|
427
|
+
if (typeof to !== "string" || to === "") {
|
|
428
|
+
return {
|
|
429
|
+
ok: false,
|
|
430
|
+
error: new Error("[@pactor-app/app] navigate \u52A8\u4F5C\u7F3A\u5C11 params.to\uFF08string\uFF09")
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
options.navigate(to);
|
|
434
|
+
return { ok: true };
|
|
435
|
+
});
|
|
436
|
+
upsertAll(actions, options.actions);
|
|
437
|
+
const services = new Registry("ServiceRegistry");
|
|
438
|
+
upsertAll(services, options.services);
|
|
439
|
+
const capabilities = new Registry("CapabilityRegistry");
|
|
440
|
+
upsertAll(capabilities, options.capabilities);
|
|
441
|
+
return {
|
|
442
|
+
components,
|
|
443
|
+
actions,
|
|
444
|
+
services,
|
|
445
|
+
capabilities,
|
|
446
|
+
overlayManager,
|
|
447
|
+
uiBridge,
|
|
448
|
+
interactionKit,
|
|
449
|
+
httpAdapter: wrapHttpAdapter(
|
|
450
|
+
createRuntimeHttpAdapter(options.authTokenProvider),
|
|
451
|
+
options.httpAdapter
|
|
452
|
+
)
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
370
456
|
// src/application.ts
|
|
371
457
|
var ReactRouterBinding = class {
|
|
372
458
|
constructor() {
|
|
@@ -412,17 +498,6 @@ var ReactRouterBinding = class {
|
|
|
412
498
|
function isRecord(value) {
|
|
413
499
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
414
500
|
}
|
|
415
|
-
function upsert(registry, name, item) {
|
|
416
|
-
if (registry.has(name)) {
|
|
417
|
-
registry.unregister(name);
|
|
418
|
-
}
|
|
419
|
-
registry.register(name, item);
|
|
420
|
-
}
|
|
421
|
-
function upsertAll(registry, entries) {
|
|
422
|
-
for (const [name, item] of Object.entries(entries ?? {})) {
|
|
423
|
-
upsert(registry, name, item);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
501
|
function createResourceHttpAdapter(authTokenProvider) {
|
|
427
502
|
const base = createFetchAdapter();
|
|
428
503
|
if (authTokenProvider === void 0) {
|
|
@@ -439,24 +514,6 @@ function createResourceHttpAdapter(authTokenProvider) {
|
|
|
439
514
|
});
|
|
440
515
|
};
|
|
441
516
|
}
|
|
442
|
-
function createRuntimeHttpAdapter(authTokenProvider) {
|
|
443
|
-
const base = createFetchHttpAdapter();
|
|
444
|
-
if (authTokenProvider === void 0) {
|
|
445
|
-
return base;
|
|
446
|
-
}
|
|
447
|
-
return {
|
|
448
|
-
async request(config) {
|
|
449
|
-
const token = await authTokenProvider();
|
|
450
|
-
if (token === void 0 || token === "") {
|
|
451
|
-
return base.request(config);
|
|
452
|
-
}
|
|
453
|
-
return base.request({
|
|
454
|
-
...config,
|
|
455
|
-
headers: { ...config.headers, authorization: `Bearer ${token}` }
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
517
|
var MENU_TYPES = /* @__PURE__ */ new Set(["group", "page", "link"]);
|
|
461
518
|
function sanitizeMenus(raw) {
|
|
462
519
|
if (!Array.isArray(raw)) {
|
|
@@ -513,42 +570,29 @@ function createPactorApplication(options) {
|
|
|
513
570
|
}
|
|
514
571
|
const { appId } = options;
|
|
515
572
|
const routerOptions = options.router ?? {};
|
|
516
|
-
const overlayManager = new OverlayManager();
|
|
517
|
-
const uiBridge = createUiBridge();
|
|
518
573
|
const permissionStore = new PermissionStore();
|
|
519
574
|
const layoutRegistry = (options.layoutRegistry ?? options.ui?.layoutRegistry)?.() ?? createShadcnLayoutRegistry();
|
|
520
|
-
const interactionKit = options.interactionKit ?? options.ui?.interactionKit ?? {
|
|
521
|
-
Provider: ShadcnInteractionProvider,
|
|
522
|
-
OverlayHost: ShadcnOverlayHost
|
|
523
|
-
};
|
|
524
575
|
const navigation = new ReactRouterBinding();
|
|
576
|
+
const assembly = createPactorAssembly({
|
|
577
|
+
componentRegistry: options.componentRegistry,
|
|
578
|
+
ui: options.ui,
|
|
579
|
+
interactionKit: options.interactionKit,
|
|
580
|
+
components: options.components,
|
|
581
|
+
actions: options.actions,
|
|
582
|
+
services: options.services,
|
|
583
|
+
capabilities: options.capabilities,
|
|
584
|
+
authTokenProvider: options.authTokenProvider,
|
|
585
|
+
httpAdapter: options.httpAdapter,
|
|
586
|
+
navigate: (to) => navigation.push(to)
|
|
587
|
+
});
|
|
588
|
+
const { components, actions, services, capabilities, httpAdapter } = assembly;
|
|
589
|
+
const { overlayManager, uiBridge, interactionKit } = assembly;
|
|
525
590
|
const loader = options.loader ?? new HttpDslResourceLoader({
|
|
526
591
|
baseUrl: options.api?.baseURL,
|
|
527
592
|
adapter: createResourceHttpAdapter(options.authTokenProvider)
|
|
528
593
|
});
|
|
529
|
-
const httpAdapter = createRuntimeHttpAdapter(options.authTokenProvider);
|
|
530
594
|
const permissionAdapter = createPermissionAdapter(permissionStore);
|
|
531
595
|
const routerAdapter = createRouterAdapter(navigation);
|
|
532
|
-
const components = (options.componentRegistry ?? options.ui?.componentRegistry)?.() ?? createShadcnComponentRegistry();
|
|
533
|
-
upsertAll(components, options.components);
|
|
534
|
-
const actions = new Registry("ActionRegistry");
|
|
535
|
-
registerInteractionActions(actions, overlayManager, uiBridge);
|
|
536
|
-
upsert(actions, "navigate", (action) => {
|
|
537
|
-
const to = action.params?.["to"];
|
|
538
|
-
if (typeof to !== "string" || to === "") {
|
|
539
|
-
return {
|
|
540
|
-
ok: false,
|
|
541
|
-
error: new Error("[@pactor-app/app] navigate \u52A8\u4F5C\u7F3A\u5C11 params.to\uFF08string\uFF09")
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
navigation.push(to);
|
|
545
|
-
return { ok: true };
|
|
546
|
-
});
|
|
547
|
-
upsertAll(actions, options.actions);
|
|
548
|
-
const services = new Registry("ServiceRegistry");
|
|
549
|
-
upsertAll(services, options.services);
|
|
550
|
-
const capabilities = new Registry("CapabilityRegistry");
|
|
551
|
-
upsertAll(capabilities, options.capabilities);
|
|
552
596
|
let session = null;
|
|
553
597
|
const handle = {
|
|
554
598
|
appId,
|
|
@@ -663,10 +707,170 @@ function createPactorApplication(options) {
|
|
|
663
707
|
}
|
|
664
708
|
};
|
|
665
709
|
}
|
|
710
|
+
|
|
711
|
+
// src/embedded.tsx
|
|
712
|
+
import { createI18nContext as createI18nContext2, isDslSourceRef } from "@pactor-app/core";
|
|
713
|
+
import { createPermissionAdapter as createPermissionAdapter2, PermissionStore as PermissionStore2 } from "@pactor-app/permission";
|
|
714
|
+
import {
|
|
715
|
+
createDefaultPermissionAdapter,
|
|
716
|
+
createPageRuntime as createPageRuntime2,
|
|
717
|
+
DslSourceResolver,
|
|
718
|
+
I18nContextProvider as I18nContextProvider2,
|
|
719
|
+
PageRuntimeView as PageRuntimeView2
|
|
720
|
+
} from "@pactor-app/runtime";
|
|
721
|
+
import {
|
|
722
|
+
useEffect as useEffect3,
|
|
723
|
+
useRef,
|
|
724
|
+
useState as useState3
|
|
725
|
+
} from "react";
|
|
726
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
727
|
+
function createPactorPage(options = {}) {
|
|
728
|
+
const assembly = createPactorAssembly({
|
|
729
|
+
...options,
|
|
730
|
+
// 嵌入模式:navigate 退化为自然跳转(设计决策 D2,不注入宿主路由对象)
|
|
731
|
+
navigate: (to) => {
|
|
732
|
+
if (typeof window !== "undefined") {
|
|
733
|
+
window.location.assign(to);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
let permission;
|
|
738
|
+
if (options.permission !== void 0) {
|
|
739
|
+
permission = options.permission;
|
|
740
|
+
} else if (options.permissions !== void 0) {
|
|
741
|
+
const store = new PermissionStore2();
|
|
742
|
+
store.setPermissions(options.permissions);
|
|
743
|
+
permission = createPermissionAdapter2(store);
|
|
744
|
+
} else {
|
|
745
|
+
permission = createDefaultPermissionAdapter();
|
|
746
|
+
}
|
|
747
|
+
const i18n = createI18nContext2({
|
|
748
|
+
locale: options.locale,
|
|
749
|
+
defaultLocale: options.defaultLocale,
|
|
750
|
+
messages: options.messages
|
|
751
|
+
});
|
|
752
|
+
function createRuntime(pageDsl, route) {
|
|
753
|
+
return createPageRuntime2(pageDsl, {
|
|
754
|
+
components: assembly.components,
|
|
755
|
+
actions: assembly.actions,
|
|
756
|
+
services: assembly.services,
|
|
757
|
+
capabilities: assembly.capabilities,
|
|
758
|
+
permission,
|
|
759
|
+
http: assembly.httpAdapter,
|
|
760
|
+
route: { params: route?.params ?? {}, query: route?.query ?? {} },
|
|
761
|
+
locale: options.locale ?? "zh-CN",
|
|
762
|
+
defaultLocale: options.defaultLocale ?? "zh-CN",
|
|
763
|
+
messages: options.messages ?? {}
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
return function ConfiguredPactorPage(props) {
|
|
767
|
+
return /* @__PURE__ */ jsx5(EmbeddedPage, { assembly, options, i18n, createRuntime, resolvePage: options.loader ? resolvePage : void 0, ...props });
|
|
768
|
+
};
|
|
769
|
+
async function resolvePage(pageId) {
|
|
770
|
+
if (!options.loader) {
|
|
771
|
+
throw new Error("[@pactor-app/app] PactorPage: \u6309 pageId \u52A0\u8F7D\u9700\u8981 options.loader");
|
|
772
|
+
}
|
|
773
|
+
const resource = await options.loader.loadPage(pageId);
|
|
774
|
+
return resource.schema;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
function PactorPage(props) {
|
|
778
|
+
const { pageId, pageDsl, route, ...options } = props;
|
|
779
|
+
const factoryRef = useRef(null);
|
|
780
|
+
if (factoryRef.current === null) {
|
|
781
|
+
factoryRef.current = createPactorPage(options);
|
|
782
|
+
}
|
|
783
|
+
const ConfiguredPage = factoryRef.current;
|
|
784
|
+
return /* @__PURE__ */ jsx5(ConfiguredPage, { pageId, pageDsl, route });
|
|
785
|
+
}
|
|
786
|
+
function EmbeddedPage({
|
|
787
|
+
assembly,
|
|
788
|
+
options,
|
|
789
|
+
i18n,
|
|
790
|
+
createRuntime,
|
|
791
|
+
resolvePage,
|
|
792
|
+
pageId,
|
|
793
|
+
pageDsl,
|
|
794
|
+
route
|
|
795
|
+
}) {
|
|
796
|
+
const [state, setState] = useState3({ status: "loading" });
|
|
797
|
+
const [retryTick, setRetryTick] = useState3(0);
|
|
798
|
+
const onError = options.onError;
|
|
799
|
+
useEffect3(() => {
|
|
800
|
+
let cancelled = false;
|
|
801
|
+
let runtime = null;
|
|
802
|
+
void (async () => {
|
|
803
|
+
try {
|
|
804
|
+
let resolved = pageDsl;
|
|
805
|
+
if (resolved === void 0) {
|
|
806
|
+
if (pageId === void 0) {
|
|
807
|
+
throw new Error("[@pactor-app/app] PactorPage: pageId \u4E0E pageDsl \u5FC5\u4F20\u5176\u4E00");
|
|
808
|
+
}
|
|
809
|
+
if (resolvePage === void 0) {
|
|
810
|
+
throw new Error("[@pactor-app/app] PactorPage: \u6309 pageId \u52A0\u8F7D\u9700\u8981 options.loader");
|
|
811
|
+
}
|
|
812
|
+
resolved = await resolvePage(pageId);
|
|
813
|
+
} else if (isDslSourceRef(resolved)) {
|
|
814
|
+
const resolver = new DslSourceResolver({
|
|
815
|
+
services: assembly.services,
|
|
816
|
+
http: assembly.httpAdapter,
|
|
817
|
+
getScope: () => ({
|
|
818
|
+
route: { params: route?.params ?? {}, query: route?.query ?? {} }
|
|
819
|
+
})
|
|
820
|
+
});
|
|
821
|
+
resolved = await resolver.resolve(resolved);
|
|
822
|
+
}
|
|
823
|
+
if (cancelled) {
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
runtime = createRuntime(resolved, route);
|
|
827
|
+
setState({ status: "ready", runtime });
|
|
828
|
+
void runtime.ready();
|
|
829
|
+
void runtime.show();
|
|
830
|
+
} catch (cause) {
|
|
831
|
+
if (!cancelled) {
|
|
832
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
833
|
+
onError?.(error);
|
|
834
|
+
setState({ status: "error", error });
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
})();
|
|
838
|
+
return () => {
|
|
839
|
+
cancelled = true;
|
|
840
|
+
if (runtime !== null && !runtime.destroyed) {
|
|
841
|
+
void runtime.hide();
|
|
842
|
+
void runtime.destroy();
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
}, [pageId, pageDsl, retryTick]);
|
|
846
|
+
const InteractionProvider = assembly.interactionKit.Provider;
|
|
847
|
+
const OverlayHost = assembly.interactionKit.OverlayHost;
|
|
848
|
+
let content;
|
|
849
|
+
if (state.status === "loading") {
|
|
850
|
+
content = /* @__PURE__ */ jsx5("div", { className: "pactor-app-page-loading", children: /* @__PURE__ */ jsx5(BootstrapSpinner, { style: { minHeight: 0, padding: 48 } }) });
|
|
851
|
+
} else if (state.status === "error") {
|
|
852
|
+
content = /* @__PURE__ */ jsx5(
|
|
853
|
+
ResultView,
|
|
854
|
+
{
|
|
855
|
+
className: "pactor-app-page-load-error",
|
|
856
|
+
title: "\u9875\u9762\u52A0\u8F7D\u5931\u8D25",
|
|
857
|
+
subTitle: state.error.message,
|
|
858
|
+
extra: /* @__PURE__ */ jsx5(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: "\u91CD\u8BD5" })
|
|
859
|
+
}
|
|
860
|
+
);
|
|
861
|
+
} else {
|
|
862
|
+
content = /* @__PURE__ */ jsx5(PageErrorBoundary, { children: /* @__PURE__ */ jsx5(PageRuntimeView2, { runtime: state.runtime, children: resolvePage !== void 0 ? /* @__PURE__ */ jsx5(OverlayHost, { manager: assembly.overlayManager, resolvePage }) : /* @__PURE__ */ jsx5(OverlayHost, { manager: assembly.overlayManager }) }) });
|
|
863
|
+
}
|
|
864
|
+
return /* @__PURE__ */ jsx5(I18nContextProvider2, { value: i18n, children: /* @__PURE__ */ jsx5(InteractionProvider, { bridge: assembly.uiBridge, children: content }) });
|
|
865
|
+
}
|
|
666
866
|
export {
|
|
667
867
|
Application,
|
|
668
868
|
DslPageLoader,
|
|
869
|
+
PactorPage,
|
|
669
870
|
PageErrorBoundary,
|
|
670
871
|
ReactRouterBinding,
|
|
671
|
-
createPactorApplication
|
|
872
|
+
createPactorApplication,
|
|
873
|
+
createPactorPage,
|
|
874
|
+
createRuntimeHttpAdapter,
|
|
875
|
+
wrapHttpAdapter
|
|
672
876
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pactor-app/app",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Pactor application: one-stop composition layer (createPactorApplication) wiring loader, bootstrap, registries, router, layout, interaction and page runtimes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pactor",
|
|
@@ -46,14 +46,14 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@pactor-app/core": "
|
|
50
|
-
"@pactor-app/expression": "
|
|
51
|
-
"@pactor-app/
|
|
52
|
-
"@pactor-app/
|
|
53
|
-
"@pactor-app/
|
|
54
|
-
"@pactor-app/
|
|
55
|
-
"@pactor-app/
|
|
56
|
-
"@pactor-app/
|
|
49
|
+
"@pactor-app/core": "1.1.0",
|
|
50
|
+
"@pactor-app/expression": "1.1.0",
|
|
51
|
+
"@pactor-app/runtime": "1.1.0",
|
|
52
|
+
"@pactor-app/schema": "1.1.0",
|
|
53
|
+
"@pactor-app/permission": "1.1.0",
|
|
54
|
+
"@pactor-app/resource": "1.1.0",
|
|
55
|
+
"@pactor-app/ui": "1.1.0",
|
|
56
|
+
"@pactor-app/router": "1.1.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"react": ">=18",
|