@pactor-app/app 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,680 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Application: () => Application,
24
+ DslPageLoader: () => DslPageLoader,
25
+ PageErrorBoundary: () => PageErrorBoundary,
26
+ ReactRouterBinding: () => ReactRouterBinding,
27
+ createPactorApplication: () => createPactorApplication
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // 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
+ var import_layout2 = require("@pactor-app/ui/layout");
36
+ var import_permission = require("@pactor-app/permission");
37
+ var import_resource = require("@pactor-app/resource");
38
+ var import_router2 = require("@pactor-app/router");
39
+ var import_runtime3 = require("@pactor-app/runtime");
40
+ var import_react5 = require("react");
41
+ var import_client = require("react-dom/client");
42
+
43
+ // src/app-shell.tsx
44
+ var import_core = require("@pactor-app/core");
45
+ var import_layout = require("@pactor-app/ui/layout");
46
+ var import_router = require("@pactor-app/router");
47
+ var import_react3 = require("@pactor-app/router/react");
48
+ var import_runtime2 = require("@pactor-app/runtime");
49
+ var import_react4 = require("react");
50
+ var import_react_router_dom = require("react-router-dom");
51
+
52
+ // src/feedback.tsx
53
+ var import_jsx_runtime = require("react/jsx-runtime");
54
+ var centerStyle = {
55
+ minHeight: "100vh",
56
+ display: "flex",
57
+ alignItems: "center",
58
+ justifyContent: "center"
59
+ };
60
+ function BootstrapSpinner({
61
+ style
62
+ }) {
63
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pactor-app-spin", style: { ...centerStyle, ...style }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
64
+ "svg",
65
+ {
66
+ width: "32",
67
+ height: "32",
68
+ viewBox: "0 0 32 32",
69
+ role: "status",
70
+ "aria-label": "\u52A0\u8F7D\u4E2D",
71
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
72
+ "circle",
73
+ {
74
+ cx: "16",
75
+ cy: "16",
76
+ r: "12",
77
+ fill: "none",
78
+ stroke: "#1677ff",
79
+ strokeWidth: "3",
80
+ strokeLinecap: "round",
81
+ strokeDasharray: "56",
82
+ strokeDashoffset: "28",
83
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
84
+ "animateTransform",
85
+ {
86
+ attributeName: "transform",
87
+ type: "rotate",
88
+ from: "0 16 16",
89
+ to: "360 16 16",
90
+ dur: "0.8s",
91
+ repeatCount: "indefinite"
92
+ }
93
+ )
94
+ }
95
+ )
96
+ }
97
+ ) });
98
+ }
99
+ function ResultView({
100
+ className,
101
+ title,
102
+ subTitle,
103
+ extra
104
+ }) {
105
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: { ...centerStyle, padding: 24 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { textAlign: "center", maxWidth: 480 }, children: [
106
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 24, fontWeight: 600, marginBottom: 8 }, children: title }),
107
+ subTitle !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { color: "rgba(0, 0, 0, 0.45)", marginBottom: 16 }, children: subTitle }),
108
+ extra
109
+ ] }) });
110
+ }
111
+ function PrimaryButton({
112
+ onClick,
113
+ children
114
+ }) {
115
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
116
+ "button",
117
+ {
118
+ type: "button",
119
+ onClick: () => onClick?.(),
120
+ style: {
121
+ padding: "6px 16px",
122
+ border: "none",
123
+ borderRadius: 6,
124
+ background: "#1677ff",
125
+ color: "#fff",
126
+ fontSize: 14,
127
+ cursor: "pointer"
128
+ },
129
+ children
130
+ }
131
+ );
132
+ }
133
+
134
+ // src/page-loader.tsx
135
+ var import_runtime = require("@pactor-app/runtime");
136
+ var import_react2 = require("react");
137
+
138
+ // src/error-boundary.tsx
139
+ var import_react = require("react");
140
+ var import_jsx_runtime2 = require("react/jsx-runtime");
141
+ var PageErrorBoundary = class extends import_react.Component {
142
+ constructor() {
143
+ super(...arguments);
144
+ this.state = { error: null };
145
+ }
146
+ static getDerivedStateFromError(error) {
147
+ return { error };
148
+ }
149
+ componentDidCatch(error, info) {
150
+ console.error("[@pactor-app/app] \u9875\u9762\u6E32\u67D3\u5F02\u5E38", error, info.componentStack);
151
+ }
152
+ render() {
153
+ const { error } = this.state;
154
+ if (error !== null) {
155
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
156
+ ResultView,
157
+ {
158
+ className: "pactor-app-page-render-error",
159
+ title: "\u9875\u9762\u6E32\u67D3\u5F02\u5E38",
160
+ subTitle: error.message,
161
+ extra: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { onClick: () => this.setState({ error: null }), children: "\u91CD\u8BD5" })
162
+ }
163
+ );
164
+ }
165
+ return this.props.children;
166
+ }
167
+ };
168
+
169
+ // src/page-loader.tsx
170
+ var import_jsx_runtime3 = require("react/jsx-runtime");
171
+ function DslPageLoader({ app, pageId, route }) {
172
+ const [state, setState] = (0, import_react2.useState)({ status: "loading" });
173
+ const [retryTick, setRetryTick] = (0, import_react2.useState)(0);
174
+ (0, import_react2.useEffect)(() => {
175
+ let cancelled = false;
176
+ let runtime = null;
177
+ void (async () => {
178
+ try {
179
+ const pageDsl = await app.resolvePage(pageId);
180
+ if (cancelled) {
181
+ return;
182
+ }
183
+ runtime = app.createPageRuntime(pageDsl, route);
184
+ setState({ status: "ready", runtime });
185
+ void runtime.ready();
186
+ void runtime.show();
187
+ } catch (cause) {
188
+ if (!cancelled) {
189
+ setState({
190
+ status: "error",
191
+ error: cause instanceof Error ? cause : new Error(String(cause))
192
+ });
193
+ }
194
+ }
195
+ })();
196
+ return () => {
197
+ cancelled = true;
198
+ if (runtime !== null && !runtime.destroyed) {
199
+ void runtime.hide();
200
+ void runtime.destroy();
201
+ }
202
+ };
203
+ }, [app, pageId, retryTick]);
204
+ if (state.status === "loading") {
205
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "pactor-app-page-loading", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BootstrapSpinner, { style: { minHeight: 0, padding: 48 } }) });
206
+ }
207
+ if (state.status === "error") {
208
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
209
+ ResultView,
210
+ {
211
+ className: "pactor-app-page-load-error",
212
+ title: "\u9875\u9762\u52A0\u8F7D\u5931\u8D25",
213
+ subTitle: state.error.message,
214
+ extra: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: "\u91CD\u8BD5" })
215
+ }
216
+ );
217
+ }
218
+ const OverlayHostView = app.interactionKit.OverlayHost;
219
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PageErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_runtime.PageRuntimeView, { runtime: state.runtime, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
220
+ OverlayHostView,
221
+ {
222
+ manager: app.overlayManager,
223
+ resolvePage: app.resolvePage
224
+ }
225
+ ) }) });
226
+ }
227
+
228
+ // src/app-shell.tsx
229
+ var import_jsx_runtime4 = require("react/jsx-runtime");
230
+ function Application({ app }) {
231
+ const [state, setState] = (0, import_react4.useState)({ status: "loading" });
232
+ const [retryTick, setRetryTick] = (0, import_react4.useState)(0);
233
+ (0, import_react4.useEffect)(() => {
234
+ let cancelled = false;
235
+ void app.loadSession().then(
236
+ (session) => {
237
+ if (!cancelled) {
238
+ setState({ status: "ready", session });
239
+ }
240
+ },
241
+ (cause) => {
242
+ if (!cancelled) {
243
+ setState({
244
+ status: "error",
245
+ error: cause instanceof Error ? cause : new Error(String(cause))
246
+ });
247
+ }
248
+ }
249
+ );
250
+ return () => {
251
+ cancelled = true;
252
+ };
253
+ }, [app, retryTick]);
254
+ if (state.status === "loading") {
255
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "pactor-app-bootstrap-loading", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BootstrapSpinner, {}) });
256
+ }
257
+ if (state.status === "error") {
258
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
259
+ ResultView,
260
+ {
261
+ className: "pactor-app-bootstrap-error",
262
+ title: "\u5E94\u7528\u542F\u52A8\u5931\u8D25",
263
+ subTitle: state.error.message,
264
+ extra: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: "\u91CD\u8BD5" })
265
+ }
266
+ );
267
+ }
268
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AppShell, { app, session: state.session });
269
+ }
270
+ function AppShell({
271
+ app,
272
+ session
273
+ }) {
274
+ const Router = app.routerOptions.type === "hash" ? import_react_router_dom.HashRouter : import_react_router_dom.BrowserRouter;
275
+ const InteractionKit = app.interactionKit.Provider;
276
+ const Providers = app.providers;
277
+ const i18n = (0, import_core.createI18nContext)({
278
+ locale: session.locale,
279
+ defaultLocale: session.defaultLocale,
280
+ messages: session.messages
281
+ });
282
+ const shell = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_runtime2.I18nContextProvider, { value: i18n, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(InteractionKit, { bridge: app.uiBridge, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ShellLayout, { app, session }) }) });
283
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Router, { basename: app.routerOptions.basename, children: [
284
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RouterBridgeSync, { binding: app.navigation }),
285
+ Providers !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Providers, { children: shell }) : shell
286
+ ] });
287
+ }
288
+ function RouterBridgeSync({ binding }) {
289
+ const bridge = (0, import_react3.useReactRouterBridge)();
290
+ const location = (0, import_react_router_dom.useLocation)();
291
+ (0, import_react4.useEffect)(() => {
292
+ binding.bind(bridge, {
293
+ pathname: location.pathname,
294
+ search: location.search
295
+ });
296
+ }, [bridge, binding]);
297
+ (0, import_react4.useEffect)(() => {
298
+ binding.sync({ pathname: location.pathname, search: location.search });
299
+ }, [binding, location.pathname, location.search]);
300
+ return null;
301
+ }
302
+ function ShellLayout({
303
+ app,
304
+ session
305
+ }) {
306
+ const location = (0, import_react_router_dom.useLocation)();
307
+ const route = (0, import_router.resolveRoute)(session.menuRegistry, {
308
+ pathname: location.pathname,
309
+ search: location.search
310
+ });
311
+ const LayoutComponent = (0, import_layout.resolveLayout)(app.layoutRegistry, session.layoutType);
312
+ const outlet = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_router_dom.Routes, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
313
+ import_react_router_dom.Route,
314
+ {
315
+ path: "*",
316
+ element: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
317
+ import_react3.DynamicDslRoute,
318
+ {
319
+ registry: session.menuRegistry,
320
+ permissionChecker: app.permissionStore,
321
+ fallback: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NotFoundPage, {}),
322
+ forbidden: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ForbiddenPage, {}),
323
+ render: ({ pageId, route: pageRoute }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
324
+ DslPageLoader,
325
+ {
326
+ app,
327
+ pageId,
328
+ route: pageRoute
329
+ },
330
+ pageLoaderKey(pageId, pageRoute)
331
+ )
332
+ }
333
+ )
334
+ }
335
+ ) });
336
+ if (session.layoutType === "admin") {
337
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
338
+ LayoutComponent,
339
+ {
340
+ config: session.layoutConfig,
341
+ brand: session.brand,
342
+ registry: session.menuRegistry,
343
+ bridge: app.navigation,
344
+ route: route ?? void 0,
345
+ permissionChecker: app.permissionStore,
346
+ headerExtra: app.headerExtra,
347
+ children: outlet
348
+ }
349
+ );
350
+ }
351
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LayoutComponent, { brand: session.brand, children: outlet });
352
+ }
353
+ function pageLoaderKey(pageId, route) {
354
+ return `${pageId}|${JSON.stringify(route.params)}|${JSON.stringify(route.query)}`;
355
+ }
356
+ function NotFoundPage() {
357
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
358
+ ResultView,
359
+ {
360
+ className: "pactor-app-not-found",
361
+ title: "404",
362
+ subTitle: "\u9875\u9762\u4E0D\u5B58\u5728\u6216\u5C1A\u672A\u6CE8\u518C"
363
+ }
364
+ );
365
+ }
366
+ function ForbiddenPage() {
367
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
368
+ ResultView,
369
+ {
370
+ className: "pactor-app-forbidden",
371
+ title: "403",
372
+ subTitle: "\u6CA1\u6709\u8BBF\u95EE\u8BE5\u9875\u9762\u7684\u6743\u9650"
373
+ }
374
+ );
375
+ }
376
+
377
+ // src/application.ts
378
+ var ReactRouterBinding = class {
379
+ constructor() {
380
+ this.location = { pathname: "/", search: "" };
381
+ this.listeners = /* @__PURE__ */ new Set();
382
+ }
383
+ /** 绑定真实桥接与初始 location(RouterBridgeSync 挂载时调用) */
384
+ bind(delegate, initial) {
385
+ this.delegate = delegate;
386
+ this.location = initial;
387
+ }
388
+ /** location 变化同步并通知订阅者 */
389
+ sync(location) {
390
+ this.location = location;
391
+ for (const listener of [...this.listeners]) {
392
+ listener(location);
393
+ }
394
+ }
395
+ getLocation() {
396
+ return this.location;
397
+ }
398
+ push(to) {
399
+ if (this.delegate === void 0) {
400
+ console.warn(`[@pactor-app/app] \u8DEF\u7531\u5C1A\u672A\u6302\u8F7D\uFF0Cpush("${to}") \u5DF2\u5FFD\u7565`);
401
+ return;
402
+ }
403
+ this.delegate.push(to);
404
+ }
405
+ replace(to) {
406
+ if (this.delegate === void 0) {
407
+ console.warn(`[@pactor-app/app] \u8DEF\u7531\u5C1A\u672A\u6302\u8F7D\uFF0Creplace("${to}") \u5DF2\u5FFD\u7565`);
408
+ return;
409
+ }
410
+ this.delegate.replace(to);
411
+ }
412
+ subscribe(listener) {
413
+ this.listeners.add(listener);
414
+ return () => {
415
+ this.listeners.delete(listener);
416
+ };
417
+ }
418
+ };
419
+ function isRecord(value) {
420
+ return typeof value === "object" && value !== null && !Array.isArray(value);
421
+ }
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
+ function createResourceHttpAdapter(authTokenProvider) {
434
+ const base = (0, import_resource.createFetchAdapter)();
435
+ if (authTokenProvider === void 0) {
436
+ return base;
437
+ }
438
+ return async (request) => {
439
+ const token = await authTokenProvider();
440
+ if (token === void 0 || token === "") {
441
+ return base(request);
442
+ }
443
+ return base({
444
+ ...request,
445
+ headers: { ...request.headers, authorization: `Bearer ${token}` }
446
+ });
447
+ };
448
+ }
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
+ var MENU_TYPES = /* @__PURE__ */ new Set(["group", "page", "link"]);
468
+ function sanitizeMenus(raw) {
469
+ if (!Array.isArray(raw)) {
470
+ return [];
471
+ }
472
+ const menus = [];
473
+ for (const item of raw) {
474
+ if (!isRecord(item) || typeof item["id"] !== "string") {
475
+ continue;
476
+ }
477
+ const menu = item;
478
+ menus.push({
479
+ ...menu,
480
+ title: typeof item["title"] === "string" ? item["title"] : menu.id,
481
+ type: MENU_TYPES.has(menu.type) ? menu.type : "page",
482
+ children: item["children"] !== void 0 ? sanitizeMenus(item["children"]) : void 0
483
+ });
484
+ }
485
+ return menus;
486
+ }
487
+ var LAYOUT_MODES = ["top-side", "top-bottom", "side-full", "two-column"];
488
+ var LAYOUT_BREAKPOINTS = ["xs", "sm", "md", "lg", "xl", "xxl"];
489
+ function pickLayoutConfig(layout) {
490
+ const config = {};
491
+ for (const key of [
492
+ "header",
493
+ "sidebar",
494
+ "tabs",
495
+ "breadcrumb",
496
+ "footer",
497
+ "fixedHeader",
498
+ "fixedSider",
499
+ "collapsible",
500
+ "collapsed"
501
+ ]) {
502
+ const value = layout?.[key];
503
+ if (typeof value === "boolean") {
504
+ config[key] = value;
505
+ }
506
+ }
507
+ const mode = layout?.["mode"];
508
+ if (typeof mode === "string" && LAYOUT_MODES.includes(mode)) {
509
+ config.mode = mode;
510
+ }
511
+ const breakpoint = layout?.["breakpoint"];
512
+ if (typeof breakpoint === "string" && LAYOUT_BREAKPOINTS.includes(breakpoint)) {
513
+ config.breakpoint = breakpoint;
514
+ }
515
+ return config;
516
+ }
517
+ function createPactorApplication(options) {
518
+ if (typeof options.appId !== "string" || options.appId === "") {
519
+ throw new Error("[@pactor-app/app] createPactorApplication: appId \u5FC5\u586B");
520
+ }
521
+ const { appId } = options;
522
+ const routerOptions = options.router ?? {};
523
+ const overlayManager = new import_interaction.OverlayManager();
524
+ const uiBridge = (0, import_interaction.createUiBridge)();
525
+ const permissionStore = new import_permission.PermissionStore();
526
+ 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
+ const navigation = new ReactRouterBinding();
532
+ const loader = options.loader ?? new import_resource.HttpDslResourceLoader({
533
+ baseUrl: options.api?.baseURL,
534
+ adapter: createResourceHttpAdapter(options.authTokenProvider)
535
+ });
536
+ const httpAdapter = createRuntimeHttpAdapter(options.authTokenProvider);
537
+ const permissionAdapter = (0, import_permission.createPermissionAdapter)(permissionStore);
538
+ 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
+ let session = null;
560
+ const handle = {
561
+ appId,
562
+ overlayManager,
563
+ uiBridge,
564
+ permissionStore,
565
+ layoutRegistry,
566
+ interactionKit,
567
+ routerOptions,
568
+ providers: options.providers,
569
+ headerExtra: options.headerExtra,
570
+ navigation,
571
+ async loadSession() {
572
+ const bootstrap = await loader.loadBootstrap();
573
+ permissionStore.setPermissions(
574
+ Array.isArray(bootstrap.permissions) ? bootstrap.permissions.filter(
575
+ (code) => typeof code === "string"
576
+ ) : []
577
+ );
578
+ const menuRegistry = new import_router2.MenuRegistry(sanitizeMenus(bootstrap.menus));
579
+ const layout = isRecord(bootstrap.layout) ? bootstrap.layout : void 0;
580
+ const layoutType = options.layout ?? (typeof layout?.["type"] === "string" ? layout["type"] : void 0) ?? "admin";
581
+ const appRecord = {
582
+ id: appId,
583
+ ...isRecord(bootstrap.app) ? bootstrap.app : {}
584
+ };
585
+ const brand = options.brand ?? {
586
+ title: typeof appRecord["name"] === "string" ? appRecord["name"] : appId,
587
+ logo: void 0
588
+ };
589
+ const browserLocale = typeof navigator !== "undefined" && typeof navigator.language === "string" ? navigator.language : "zh-CN";
590
+ const locale = options.locale ?? (typeof bootstrap.locale === "string" ? bootstrap.locale : void 0) ?? browserLocale;
591
+ const defaultLocale = options.defaultLocale ?? (typeof bootstrap.defaultLocale === "string" ? bootstrap.defaultLocale : void 0) ?? "zh-CN";
592
+ const messages = options.messages ?? (isRecord(bootstrap.messages) ? bootstrap.messages : void 0) ?? {};
593
+ const next = {
594
+ bootstrap,
595
+ menuRegistry,
596
+ layoutType,
597
+ layoutConfig: pickLayoutConfig(layout),
598
+ brand,
599
+ user: isRecord(bootstrap.user) ? bootstrap.user : {},
600
+ app: appRecord,
601
+ locale,
602
+ defaultLocale,
603
+ messages
604
+ };
605
+ session = next;
606
+ return next;
607
+ },
608
+ createPageRuntime(pageDsl, route) {
609
+ return (0, import_runtime3.createPageRuntime)(pageDsl, {
610
+ components,
611
+ actions,
612
+ services,
613
+ capabilities,
614
+ permission: permissionAdapter,
615
+ router: routerAdapter,
616
+ http: httpAdapter,
617
+ route: { params: route.params, query: route.query },
618
+ user: session?.user ?? {},
619
+ app: session?.app ?? { id: appId },
620
+ locale: session?.locale ?? "zh-CN",
621
+ defaultLocale: session?.defaultLocale ?? "zh-CN",
622
+ messages: session?.messages ?? {}
623
+ });
624
+ },
625
+ async resolvePage(pageId) {
626
+ const resource = await loader.loadPage(pageId);
627
+ return resource.schema;
628
+ }
629
+ };
630
+ let root = null;
631
+ return {
632
+ appId,
633
+ mount(selector) {
634
+ const target = document.querySelector(selector);
635
+ if (target === null) {
636
+ throw new Error(`[@pactor-app/app] mount \u76EE\u6807\u5143\u7D20\u4E0D\u5B58\u5728: ${selector}`);
637
+ }
638
+ if (root !== null) {
639
+ root.unmount();
640
+ root = null;
641
+ }
642
+ root = (0, import_client.createRoot)(target);
643
+ root.render((0, import_react5.createElement)(Application, { app: handle }));
644
+ },
645
+ unmount() {
646
+ if (root !== null) {
647
+ root.unmount();
648
+ root = null;
649
+ }
650
+ },
651
+ registerComponent(name, component) {
652
+ upsert(components, name, component);
653
+ },
654
+ registerAction(name, handler) {
655
+ upsert(actions, name, handler);
656
+ },
657
+ registerService(name, handler) {
658
+ upsert(services, name, handler);
659
+ },
660
+ registerCapability(name, capability) {
661
+ upsert(capabilities, name, capability);
662
+ },
663
+ setLocale(locale, messages) {
664
+ if (session === null) {
665
+ console.warn("[@pactor-app/app] setLocale \u5728 bootstrap \u5B8C\u6210\u524D\u8C03\u7528\u5DF2\u5FFD\u7565");
666
+ return;
667
+ }
668
+ session = { ...session, locale, messages: messages ?? session.messages };
669
+ window.location.reload();
670
+ }
671
+ };
672
+ }
673
+ // Annotate the CommonJS export names for ESM import in node:
674
+ 0 && (module.exports = {
675
+ Application,
676
+ DslPageLoader,
677
+ PageErrorBoundary,
678
+ ReactRouterBinding,
679
+ createPactorApplication
680
+ });