@axewo/fin-micro 0.0.0-stage → 2.0.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.
Files changed (91) hide show
  1. package/README.md +223 -2
  2. package/cli/index.mjs +240 -0
  3. package/dist/browser.cjs +1 -0
  4. package/dist/browser.mjs +169 -0
  5. package/dist/core.cjs +1 -0
  6. package/dist/core.mjs +654 -0
  7. package/dist/iframe.cjs +1 -0
  8. package/dist/iframe.mjs +146 -0
  9. package/dist/index.cjs +1 -0
  10. package/dist/index.mjs +35 -0
  11. package/dist/router-view-impl-B1NzCGKV.mjs +76 -0
  12. package/dist/router-view-impl-BvOToV_Z.cjs +1 -0
  13. package/dist/runtime.cjs +1 -0
  14. package/dist/runtime.mjs +149 -0
  15. package/dist/sdk.cjs +1 -0
  16. package/dist/sdk.mjs +118 -0
  17. package/dist/types/browser/index.d.ts +46 -0
  18. package/dist/types/core/index.d.ts +63 -0
  19. package/dist/types/iframe/index.d.ts +77 -0
  20. package/dist/types/index.d.ts +8 -0
  21. package/dist/types/runtime/index.d.ts +21 -0
  22. package/dist/types/runtime/lifecycle.d.ts +23 -0
  23. package/dist/types/sdk/index.d.ts +397 -0
  24. package/dist/types/vue/index.d.ts +102 -0
  25. package/dist/types/vue/router-view-impl.d.ts +41 -0
  26. package/dist/types/vue/router-view.d.ts +42 -0
  27. package/dist/types/vue/tab-context.d.ts +6 -0
  28. package/dist/vue.cjs +1 -0
  29. package/dist/vue.mjs +180 -0
  30. package/package.json +91 -3
  31. package/scaffold/base/index.html +12 -0
  32. package/scaffold/base/package.json.template +33 -0
  33. package/scaffold/base/scripts/check-runtime.mjs +43 -0
  34. package/scaffold/base/src/components/.gitkeep +1 -0
  35. package/scaffold/base/src/components/AppProviders.vue +25 -0
  36. package/scaffold/base/src/hooks/.gitkeep +1 -0
  37. package/scaffold/base/src/layout/.gitkeep +1 -0
  38. package/scaffold/base/src/locales/.gitkeep +1 -0
  39. package/scaffold/base/src/locales/en.ts +12 -0
  40. package/scaffold/base/src/locales/index.ts +13 -0
  41. package/scaffold/base/src/locales/zh-CN.ts +12 -0
  42. package/scaffold/base/src/main.ts +22 -0
  43. package/scaffold/base/src/router/.gitkeep +1 -0
  44. package/scaffold/base/src/router/demo.ts +6 -0
  45. package/scaffold/base/src/router/index.ts +13 -0
  46. package/scaffold/base/src/stores/.gitkeep +1 -0
  47. package/scaffold/base/src/stores/demo.ts +12 -0
  48. package/scaffold/base/src/stores/index.ts +11 -0
  49. package/scaffold/base/src/styles/index.css +18 -0
  50. package/scaffold/base/src/types/.gitkeep +1 -0
  51. package/scaffold/base/src/utils/.gitkeep +1 -0
  52. package/scaffold/base/src/utils/appConfig.ts +49 -0
  53. package/scaffold/base/src/utils/errorUtils.ts +92 -0
  54. package/scaffold/base/src/utils/requestUtils.ts +144 -0
  55. package/scaffold/base/src/views/.gitkeep +1 -0
  56. package/scaffold/base/src/views/DemoView.vue +26 -0
  57. package/scaffold/base/tsconfig.json +16 -0
  58. package/scaffold/base/vite.config.ts +8 -0
  59. package/scaffold/host/.env.example +13 -0
  60. package/scaffold/host/src/App.vue +4 -0
  61. package/scaffold/host/src/bootstrap.ts +50 -0
  62. package/scaffold/host/src/hooks/usePlatformSession.ts +91 -0
  63. package/scaffold/host/src/layout/HostHeader.vue +69 -0
  64. package/scaffold/host/src/layout/HostLayout.vue +168 -0
  65. package/scaffold/host/src/layout/HostMenu.vue +15 -0
  66. package/scaffold/host/src/layout/HostTabs.vue +47 -0
  67. package/scaffold/host/src/layout/HostWorkspace.vue +26 -0
  68. package/scaffold/host/src/localPages.ts +45 -0
  69. package/scaffold/host/src/platform.ts +239 -0
  70. package/scaffold/host/src/router/guards.ts +128 -0
  71. package/scaffold/host/src/router/index.ts +25 -0
  72. package/scaffold/host/src/router/targets.ts +30 -0
  73. package/scaffold/host/src/router/workspace.ts +63 -0
  74. package/scaffold/host/src/styles/shell.css +761 -0
  75. package/scaffold/host/src/types/platform.ts +12 -0
  76. package/scaffold/host/src/utils/request.ts +42 -0
  77. package/scaffold/host/src/views/HomeView.vue +19 -0
  78. package/scaffold/host/src/views/LoginRoute.vue +16 -0
  79. package/scaffold/host/src/views/LoginView.vue +88 -0
  80. package/scaffold/host/src/views/NotFoundView.vue +1 -0
  81. package/scaffold/host/src/views/ProfileView.vue +24 -0
  82. package/scaffold/host/src/views/WorkspaceRoute.vue +11 -0
  83. package/scaffold/vue/src/App.vue +24 -0
  84. package/scaffold/vue/src/bootstrap.ts +67 -0
  85. package/scaffold/vue/src/bridge/auth.ts +23 -0
  86. package/scaffold/vue/src/bridge/session.ts +16 -0
  87. package/scaffold/vue/src/main.ts +13 -0
  88. package/scaffold/vue/src/router/index.ts +16 -0
  89. package/scaffold/vue/src/views/DetailView.vue +57 -0
  90. package/scaffold/vue/src/views/ListView.vue +55 -0
  91. package/scaffold/vue/src/views/NotFoundView.vue +1 -0
@@ -0,0 +1,169 @@
1
+ function x(r) {
2
+ return `#/apps/${encodeURIComponent(r.appId)}/${encodeURIComponent(r.tabId)}?route=${encodeURIComponent(r.route)}`;
3
+ }
4
+ function H(r) {
5
+ if (!r || r === "#/" || r === "#") return null;
6
+ const i = /^#\/apps\/([^/?#]+)\/([^/?#]+)\?route=([^&#]*)$/.exec(r);
7
+ if (!i) throw new Error("无效的微应用 URL");
8
+ const [, o, v, y] = i;
9
+ return {
10
+ appId: decodeURIComponent(o),
11
+ tabId: decodeURIComponent(v),
12
+ route: decodeURIComponent(y)
13
+ };
14
+ }
15
+ function J(r, i = {}) {
16
+ const o = i.window ?? window, v = i.storageKey ?? "fin-micro:tabs:v1", y = "fin-micro:navigation:v1", S = `${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`, u = (t) => {
17
+ var e;
18
+ try {
19
+ (e = i.onError) == null || e.call(i, t instanceof Error ? t : new Error(String(t)));
20
+ } catch {
21
+ }
22
+ }, j = new Set(r.apps.map((t) => t.appId)), w = (t, e) => typeof t == "string" && t.length > 0 && t.length <= e && !/[\u0000-\u001f\u007f]/.test(t);
23
+ function m(t) {
24
+ if (!t || typeof t != "object") return !1;
25
+ const e = t;
26
+ return w(e.appId, 200) && j.has(e.appId) && w(e.tabId, 500) && w(e.title, 500) && w(e.route, 8192) && e.route.startsWith("/") && !e.route.startsWith("//") && !e.route.includes("\\");
27
+ }
28
+ const U = (t) => ({
29
+ appId: t.appId,
30
+ tabId: t.tabId,
31
+ title: t.title,
32
+ route: t.route,
33
+ ...t.activeMenuId !== void 0 ? { activeMenuId: t.activeMenuId } : {}
34
+ });
35
+ function $(t) {
36
+ try {
37
+ o.sessionStorage.setItem(
38
+ v,
39
+ JSON.stringify({
40
+ version: 1,
41
+ tabs: t.tabs.map(U),
42
+ activeTabId: t.activeTabId
43
+ })
44
+ );
45
+ } catch (e) {
46
+ u(e);
47
+ }
48
+ }
49
+ function k(t, e = !1) {
50
+ if (i.url !== !1)
51
+ try {
52
+ const n = t.tabs.find((R) => R.tabId === t.activeTabId), s = n ? x(n) : "#/", a = o.history.state, d = a == null ? void 0 : a[y], f = o.location.hash === s;
53
+ if (f && (d == null ? void 0 : d.session) === S && (d == null ? void 0 : d.key) === ((n == null ? void 0 : n.key) ?? null)) return;
54
+ const c = `${o.location.pathname}${o.location.search}${s}`, b = {
55
+ ...a && typeof a == "object" ? a : {},
56
+ [y]: { session: S, key: (n == null ? void 0 : n.key) ?? null }
57
+ };
58
+ e && !f ? o.history.pushState(b, "", c) : o.history.replaceState(b, "", c);
59
+ } catch (n) {
60
+ u(n);
61
+ }
62
+ }
63
+ function A(t) {
64
+ var s;
65
+ const e = r.getState().tabs.find((a) => a.tabId === t.tabId), n = {
66
+ ...t,
67
+ title: (e == null ? void 0 : e.title) ?? ((s = i.initialLocation) == null ? void 0 : s.title) ?? `${t.appId} · ${t.route}`.slice(0, 500)
68
+ };
69
+ if (!m(n)) throw new Error("URL 包含未知应用或无效页签/路由");
70
+ r.openTab(n);
71
+ }
72
+ let p = null;
73
+ try {
74
+ p = i.initialLocation ?? (i.url === !1 ? null : H(o.location.hash));
75
+ } catch (t) {
76
+ u(t);
77
+ }
78
+ try {
79
+ const t = o.sessionStorage.getItem(v);
80
+ if (t) {
81
+ const e = JSON.parse(t);
82
+ if (!e || typeof e != "object") throw new Error("无效的页签存储");
83
+ const n = e;
84
+ if (n.version !== 1 || !Array.isArray(n.tabs) || n.tabs.length > 100)
85
+ throw new Error("不支持的页签存储版本或格式");
86
+ const s = new Set(r.getState().tabs.map((a) => a.tabId));
87
+ for (const a of n.tabs)
88
+ if (!(!m(a) || s.has(a.tabId)) && !(p && m({ ...p, title: "深链恢复" }) && p.tabId === a.tabId && (p.appId !== a.appId || p.route !== a.route)))
89
+ try {
90
+ r.openTab(U(a)), s.add(a.tabId);
91
+ } catch (d) {
92
+ u(d);
93
+ }
94
+ typeof n.activeTabId == "string" && r.activateTab(n.activeTabId);
95
+ }
96
+ } catch (t) {
97
+ u(t);
98
+ }
99
+ try {
100
+ p && A(p);
101
+ } catch (t) {
102
+ u(t);
103
+ }
104
+ let l = r.getState();
105
+ k(l), $(l);
106
+ let E = !1, h = !1;
107
+ const K = r.subscribe((t) => {
108
+ const e = l.tabs.some((n) => !t.tabs.some((s) => s.key === n.key));
109
+ l = t, $(t), E || k(t, !e);
110
+ });
111
+ let g = 0, I, L;
112
+ function T(t) {
113
+ var d;
114
+ if (h) return;
115
+ const e = ++g;
116
+ I == null || I.abort();
117
+ const n = new AbortController();
118
+ I = n;
119
+ const s = o.location.hash, a = (d = o.history.state) == null ? void 0 : d[y];
120
+ E = !0, (async () => {
121
+ await Promise.resolve();
122
+ try {
123
+ if (h || e !== g) return;
124
+ const f = H(s);
125
+ if (!f) return;
126
+ const c = r.getState().tabs.find((R) => R.tabId === f.tabId), b = {
127
+ ...f,
128
+ title: (c == null ? void 0 : c.title) ?? `${f.appId} · ${f.route}`.slice(0, 500)
129
+ };
130
+ if (!m(b)) throw new Error("URL 包含未知应用或无效页签/路由");
131
+ if (t) {
132
+ if ((a == null ? void 0 : a.session) !== S || !c || a.key !== c.key || c.appId !== b.appId || c.route !== b.route)
133
+ return;
134
+ await r.operate({
135
+ type: "activate",
136
+ target: { tabId: c.tabId, key: c.key },
137
+ signal: n.signal
138
+ });
139
+ } else
140
+ await r.operate({ type: "open", input: b, signal: n.signal });
141
+ } catch (f) {
142
+ !h && e === g && u(f);
143
+ } finally {
144
+ !h && e === g && (E = !1, l = r.getState(), k(l), $(l));
145
+ }
146
+ })();
147
+ }
148
+ const C = () => {
149
+ L = o.location.hash, T(!0);
150
+ }, M = (t) => {
151
+ const e = t.newURL, n = e ? new URL(e).hash : o.location.hash;
152
+ if (L === n) {
153
+ L = void 0;
154
+ return;
155
+ }
156
+ L = void 0, T(!1);
157
+ };
158
+ return i.url !== !1 && (o.addEventListener("popstate", C), o.addEventListener("hashchange", M)), {
159
+ /** 幂等移除本连接器的宿主订阅和浏览器事件;不清空存储、不关闭页签、不销毁宿主。 */
160
+ dispose() {
161
+ h || (h = !0, g++, I == null || I.abort(), K(), i.url !== !1 && (o.removeEventListener("popstate", C), o.removeEventListener("hashchange", M)));
162
+ }
163
+ };
164
+ }
165
+ export {
166
+ J as connectMicroBrowser,
167
+ H as decodeMicroLocation,
168
+ x as encodeMicroLocation
169
+ };
package/dist/core.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("./sdk.cjs");function Ge(Le,R={}){var Oe;const X=new Map,ye=new Map,z=e=>typeof e=="string"&&!!e.trim()&&!/[\u0000-\u001f\u007f]/.test(e),fe=e=>z(e)&&e.startsWith("/")&&!e.startsWith("//")&&!e.includes("\\"),pe=e=>e.split(/[?#]/,1)[0];for(const e of Le){let a=function(r){if(!Array.isArray(r))throw new Error("menus 必须为数组");return Object.freeze(r.map(i=>{if(!i||!z(i.menuId)||!z(i.name)||c.has(i.menuId))throw new Error("菜单标识/名称无效或菜单标识重复");if(c.add(i.menuId),i.children!==void 0){if(i.target!==void 0||!Array.isArray(i.children)||!i.children.length)throw new Error("菜单分组需要非空 children 且不能配置 target");return Object.freeze({menuId:i.menuId,name:i.name,children:a(i.children)})}if(!i.target||!z(i.target.tabId)||!fe(i.target.route))throw new Error("菜单叶节点需要有效 target");return I.add(i.menuId),b.push({pathPrefix:pe(i.target.route),menuId:i.menuId}),Object.freeze({menuId:i.menuId,name:i.name,target:Object.freeze({tabId:i.target.tabId,route:i.target.route})})}))};if(X.has(e.appId))throw new Error(`重复的 appId: ${e.appId}`);if(e.kind==="local"){if(e.entry!==void 0)throw new Error("本地应用不能配置 entry")}else{if(e.kind!==void 0&&e.kind!=="remote")throw new Error("未知应用类型");const r=new URL(e.entry);if(!["http:","https:"].includes(r.protocol))throw new Error("子应用地址必须使用 HTTP(S)")}const c=new Set,I=new Set,b=[],h=e.menus===void 0?void 0:a(e.menus);if(e.menuRoutes!==void 0&&!Array.isArray(e.menuRoutes))throw new Error("menuRoutes 必须为数组");const o=(Oe=e.menuRoutes)==null?void 0:Oe.map(r=>{if(!r||!fe(r.pathPrefix)||/[?#]/.test(r.pathPrefix)||!I.has(r.menuId))throw new Error("菜单归属规则需要有效路径与本应用可导航叶节点");return Object.freeze({pathPrefix:r.pathPrefix,menuId:r.menuId})});b.push(...(o??[]).map(r=>({...r})));const t=new Map;for(const r of b){if(r.pathPrefix=r.pathPrefix.replace(/\/+$/,"")||"/",t.has(r.pathPrefix)&&t.get(r.pathPrefix)!==r.menuId)throw new Error("菜单归属前缀冲突");t.set(r.pathPrefix,r.menuId)}ye.set(e.appId,{leaves:I,routes:b.sort((r,i)=>i.pathPrefix.length-r.pathPrefix.length)}),X.set(e.appId,Object.freeze({appId:e.appId,name:e.name,...e.kind==="local"?{kind:"local"}:{...e.kind?{kind:e.kind}:{},entry:e.entry},...h?{menus:h}:{},...o?{menuRoutes:Object.freeze(o)}:{}}))}const ae=u.createNotificationBus(),Re=Object.freeze({source:"host"}),de={on(e,a){return ae.on(e,({payload:c,metadata:I})=>U(()=>a(c,I)))},emit(e,a){ae.emit(e,{payload:a,metadata:Re})},clear:()=>ae.clear()},se=R.callTimeoutMs??3e4;if(!Number.isFinite(se)||se<=0||se>2147483647)throw new Error("callTimeoutMs 必须为不超过2147483647的正有限数");const Z=new Set;function we(e,a){if(!e||typeof e.authenticated!="boolean"||!Array.isArray(e.permissions)||!e.permissions.every(c=>typeof c=="string")||e.user!==void 0&&(!e.user||typeof e.user.id!="string"||e.user.name!==void 0&&typeof e.user.name!="string"))throw new Error("会话快照无效");return Object.freeze({authenticated:e.authenticated,permissions:Object.freeze([...e.permissions]),...e.user?{user:Object.freeze({id:e.user.id,...e.user.name!==void 0?{name:e.user.name}:{}})}:{},revision:a})}let K=we(R.session??{authenticated:!1,permissions:[]},0);function ze(e){D(),K=we(e,K.revision+1);const a=K;for(const c of[...Z]){if(a!==K)break;Z.has(c)&&U(()=>c(a))}return a}const ee=new Set,te=new Map,ve=new Map(Object.entries(R.capabilities??{}).filter(([,e])=>e!==void 0).map(([e,a])=>{const c=a;return[e,{handler:c.handler,apps:c.apps?new Set(c.apps):void 0}]})),V=new Map,B=new Map;let d={tabs:[],activeTabId:null},le=0,P=!1,G=0,Ee=Promise.resolve();const re=new Map,W=new Map,xe=e=>{var a;try{(a=R.onError)==null||a.call(R,e)}catch{}},U=e=>{try{e()}catch(a){xe(a)}},D=()=>{if(P)throw new Error("MicroHost 已销毁")},ie=()=>({tabs:[...d.tabs],activeTabId:d.activeTabId}),oe=()=>{G++;for(const e of[...ee])ee.has(e)&&U(()=>e(ie()))};function ke(e){return D(),ee.add(e),()=>{ee.delete(e)}}const be=R.canNavigate,ge=R.canOpen;function q(e){if(!ge)return;const a=Object.freeze({appId:e.appId,tabId:e.tabId,title:e.title,route:e.route,...e.activeMenuId!==void 0?{activeMenuId:e.activeMenuId}:{}});try{const c=ge(a);if(c===!0)return;c&&(typeof c=="object"||typeof c=="function")&&Promise.resolve(c).catch(()=>{})}catch{}throw new u.NavigationError("FORBIDDEN","无权访问该页面(权限策略必须同步返回 true)")}function ue(e,a=!1){var o;if(D(),!e||!z(e.title)||e.title.length>500)throw new Error("页签标题无效");if(!X.has(e.appId))throw new Error(`未知子应用: ${e.appId}`);if(!z(e.tabId)||!fe(e.route))throw new Error("需要 tabId 与应用内绝对路由");const c=ye.get(e.appId);if(e.activeMenuId!==void 0&&!c.leaves.has(e.activeMenuId))throw new Error("activeMenuId 必须指向本应用可导航叶节点");const I=pe(e.route),b=e.activeMenuId??((o=c.routes.find(t=>t.pathPrefix==="/"||I===t.pathPrefix||I.startsWith(`${t.pathPrefix}/`)))==null?void 0:o.menuId);let h=d.tabs.find(t=>t.tabId===e.tabId);if(h&&(h.appId!==e.appId||h.route!==e.route&&!a))throw new Error("tabId 已绑定到其他页面");return h&&h.route!==e.route&&(h=void 0),q(h??{...e,activeMenuId:b}),h||(h=Object.freeze({appId:e.appId,tabId:e.tabId,title:e.title,route:e.route,...b!==void 0?{activeMenuId:b}:{},key:`${e.tabId}:${++le}`})),h}function He(e){const a=ue(e);return d={tabs:d.tabs.includes(a)?d.tabs:[...d.tabs,a],activeTabId:a.tabId},oe(),a}function _e(e,a,c){if(D(),typeof a.title!="string"||!a.title.trim()||a.title.length>500||/[\u0000-\u001f\u007f]/.test(a.title))throw new Error("页签标题无效");const I=d.tabs.find(h=>h.tabId===e&&(!c||h.key===c));if(!I)return;const b=Object.freeze({...I,title:a.title});return d={...d,tabs:d.tabs.map(h=>h===I?b:h)},oe(),b}function Ce(e){D();const a=d.tabs.find(c=>c.tabId===e);return a?(q(a),d={...d,activeTabId:e},oe(),!0):!1}function Fe(e,a){var h;D();const c=d.tabs.findIndex(o=>o.tabId===e&&(!a||o.key===a));if(c<0)return!1;const I=d.tabs[c],b=d.tabs.filter(o=>o!==I);if(d={tabs:b,activeTabId:d.activeTabId===e?((h=b[Math.min(c,b.length-1)])==null?void 0:h.tabId)??null:d.activeTabId},me(I.key),!b.some(o=>o.appId===I.appId)){for(const o of[...B.get(I.appId)??[]])U(o);B.delete(I.appId),te.delete(I.appId)}return oe(),!0}function me(e){re.delete(e),W.delete(e);for(const a of[...V.get(e)??[]])U(a);V.delete(e)}function $e(e){return Y(e)}function Y(e,a,c,I=!1,b,h=!1){var o;try{if(P)throw new u.NavigationError("HOST_DISPOSED","MicroHost 已销毁");if(!e||!["open","activate","refresh","close","closeMany","back"].includes(e.type))throw new u.NavigationError("INVALID_OPERATION","导航命令无效");const t={...e,..."target"in e&&e.target?{target:{...e.target}}:{},..."anchor"in e&&e.anchor?{anchor:{...e.anchor}}:{}},r=n=>!!n&&z(n.tabId)&&(n.key===void 0||z(n.key));if(["activate","refresh","close"].includes(t.type)&&(!("target"in t)||!r(t.target)))throw new u.NavigationError("INVALID_OPERATION","导航需要合法目标引用");if("target"in t&&t.target!==void 0&&!r(t.target)||"anchor"in t&&t.anchor!==void 0&&!r(t.anchor))throw new u.NavigationError("INVALID_OPERATION","导航引用无效");if(t.type==="closeMany"&&t.exclude!==void 0){if(!Array.isArray(t.exclude)||!t.exclude.every(r))throw new u.NavigationError("INVALID_OPERATION","批量排除引用无效");t.exclude=Object.freeze(t.exclude.map(n=>{var m;return Object.freeze({tabId:n.tabId,...n.key!==void 0?{key:n.key}:{key:(m=d.tabs.find(v=>v.tabId===n.tabId))==null?void 0:m.key}})}))}if(t.type==="open"){const n=t.input;if(!n)throw new u.NavigationError("INVALID_OPERATION","导航目标无效");t.input=Object.freeze({appId:n.appId,tabId:n.tabId,title:n.title,route:n.route,...n.activeMenuId!==void 0?{activeMenuId:n.activeMenuId}:{}})}if("closeFallback"in t&&t.closeFallback!==void 0){if(!r(t.closeFallback))throw new u.NavigationError("INVALID_OPERATION","关闭回落引用无效");const n=t.closeFallback;t.closeFallback=Object.freeze({tabId:n.tabId,key:n.key??((o=d.tabs.find(m=>m.tabId===n.tabId))==null?void 0:o.key)})}"fallback"in t&&t.fallback&&(t.fallback=Object.freeze({...t.fallback})),"target"in t&&t.target&&Object.freeze(t.target),"anchor"in t&&t.anchor&&Object.freeze(t.anchor),Object.freeze(t);const i=n=>d.tabs.find(m=>n?m.tabId===n.tabId&&(!n.key||m.key===n.key):m.tabId===d.activeTabId),w="target"in t?i(t.target):void 0,E=t.type==="closeMany"&&t.scope!=="all"?t.anchor?i(t.anchor):c?d.tabs.find(n=>n.key===c):i():void 0,S=i(),f=t.type==="open"?d.tabs.find(n=>n.tabId===t.input.tabId):void 0,y=h&&c?d.tabs.find(n=>n.key===c):void 0,k=y&&a?Object.freeze({appId:a,tab:Object.freeze({...y})}):void 0,x=h&&t.type==="open"&&!!a&&t.input.appId!==a,j=()=>{if(!(!x||t.type!=="open")){try{const n=k&&(be==null?void 0:be(k,t.input));if(n===!0)return;n&&(typeof n=="object"||typeof n=="function")&&Promise.resolve(n).catch(()=>{})}catch{}throw new u.NavigationError("FORBIDDEN","无权跨应用导航(权限策略必须同步返回 true)")}},H=n=>!a||n.appId===a;if(w&&!H(w)||E&&!H(E)||t.type==="open"&&a&&t.input.appId!==a&&!x||t.type==="back"&&t.fallback&&a&&t.fallback.appId!==a)throw new u.NavigationError("FORBIDDEN","页面只能操作本应用");if(t.type==="closeMany"&&!["all","others","left","right"].includes(t.scope))throw new u.NavigationError("INVALID_OPERATION","批量范围无效");const _=E?d.tabs.indexOf(E):-1,J=t.type==="closeMany"?d.tabs.filter((n,m)=>{var v;return H(n)&&!((v=t.exclude)!=null&&v.some(F=>F.tabId===n.tabId&&F.key===n.key))&&(t.scope==="all"||_>=0&&(t.scope==="others"?n.key!==E.key:t.scope==="left"?m<_:m>_))}):[],g=t.type==="back"?w??(!("target"in t)||!t.target?S:void 0):w,C=async()=>{var Ne,Ae,Te,Pe,Me,De;const n=s=>({status:s,affected:[]});if(P)throw new u.NavigationError("HOST_DISPOSED","MicroHost 已销毁");if((Ne=t.signal)!=null&&Ne.aborted)return n("stale");if(c&&!I&&(b!=null&&b()||!d.tabs.some(s=>s.key===c)))throw new u.NavigationError("PAGE_RELEASED","页面上下文已释放");if(t.type==="open"&&(f?!d.tabs.some(s=>s.key===f.key):d.tabs.some(s=>s.tabId===t.input.tabId))||g&&!d.tabs.some(s=>s.key===g.key)||E&&!d.tabs.some(s=>s.key===E.key)||J.some(s=>!d.tabs.some(O=>O.key===s.key)))return n("stale");if(t.type!=="open"&&t.type!=="closeMany"&&!g)return n("noop");const m=G;if(j(),c&&!I&&(b!=null&&b()||!d.tabs.some(s=>s.key===c)))throw new u.NavigationError("PAGE_RELEASED","页面上下文已释放");if(G!==m||P||(Ae=t.signal)!=null&&Ae.aborted)return n("stale");const v=d,F=G;let p=[...d.tabs],l,M=[],$=d.activeTabId;try{if(t.type==="open"&&(l=ue(t.input,!0),f&&f.key!==l.key?(M=[f],p=p.map(s=>s.key===f.key?l:s)):p.some(s=>s.key===l.key)||p.push(l),$=l.tabId),t.type==="activate"&&(l=g,q(l),$=l.tabId),t.type==="refresh"&&(q(g),M=[g],l=Object.freeze({...g,key:`${g.tabId}:${++le}`}),p=p.map(s=>s.key===g.key?l:s)),(t.type==="close"||t.type==="back")&&(M=[g]),t.type==="closeMany"&&(M=J),M.length&&t.type!=="refresh"&&t.type!=="open"){const s=new Set(M.map(N=>N.key)),O=v.tabs.findIndex(N=>N.tabId===v.activeTabId);if(p=p.filter(N=>!s.has(N.key)),t.type==="back"){const N=W.get(g.key);l=p.find(T=>T.key===N&&H(T)),!l&&t.fallback&&(l=ue(t.fallback),s.has(l.key)&&(l=Object.freeze({...l,key:`${l.tabId}:${++le}`})),p.some(T=>T.key===l.key)||p.push(l));const A=v.tabs.filter(T=>H(T)),L=A.findIndex(T=>T.key===g.key);l??(l=A.slice(0,L).reverse().find(T=>p.some(ne=>ne.key===T.key))??A.slice(L+1).find(T=>p.some(ne=>ne.key===T.key))),l??(l=p[Math.min(O,p.length-1)]),l&&q(l),$=(l==null?void 0:l.tabId)??null}else if(M.some(N=>N.tabId===$)){const N="closeFallback"in t?t.closeFallback:void 0,A=N?p.find(L=>L.tabId===N.tabId&&L.key===N.key&&H(L)):void 0;A&&(q(A),l=A),$=((Te=A??p[Math.min(O,p.length-1)])==null?void 0:Te.tabId)??null}}}catch(s){throw s instanceof u.NavigationError?s:new u.NavigationError("INVALID_OPERATION","导航参数无效")}if(p.length===v.tabs.length&&p.every((s,O)=>s.key===v.tabs[O].key)&&$===v.activeTabId)return n("noop");const he=[...M],ce=v.tabs.find(s=>s.tabId===v.activeTabId);ce&&ce.tabId!==$&&!he.some(s=>s.key===ce.key)&&he.push(ce);for(const s of he)for(const O of[...re.get(s.key)??[]]){let N;const A=t.signal;let L=()=>{};try{const T=Promise.resolve(O({operation:t,tab:s})),ne=new Promise(Se=>{if(!A)return;const je=()=>Se();A.addEventListener("abort",je,{once:!0}),L=()=>A.removeEventListener("abort",je),A.aborted&&Se()});N=await Promise.race([T,ne])}catch{if(A!=null&&A.aborted)return n("stale");throw new u.NavigationError("GUARD_FAILED","离页守卫执行失败")}finally{L()}if(G!==F||P||(Pe=t.signal)!=null&&Pe.aborted)return n("stale");if(N===!1)return n("cancelled")}if(G!==F||P||(Me=t.signal)!=null&&Me.aborted)return n("stale");if(b!=null&&b())throw new u.NavigationError("PAGE_RELEASED","页面上下文已释放");if(j(),l&&q(l),b!=null&&b())throw new u.NavigationError("PAGE_RELEASED","页面上下文已释放");if(G!==F||P||(De=t.signal)!=null&&De.aborted)return n("stale");if(d={tabs:p,activeTabId:$},t.type==="open"&&l&&c&&!x&&l.key!==c&&!W.has(l.key)&&W.set(l.key,c),t.type==="refresh"&&l){const s=W.get(g.key);s&&W.set(l.key,s)}for(const s of M)me(s.key);for(const s of new Set(M.map(O=>O.appId)))if(!p.some(O=>O.appId===s)){for(const O of[...B.get(s)??[]])U(O);B.delete(s),te.delete(s)}const Ie=[...M,...p.filter(s=>!v.tabs.some(O=>O.key===s.key))];return!Ie.length&&l&&Ie.push(l),oe(),{status:"committed",affected:Ie.map(s=>({tabId:s.tabId,key:s.key})),...l?{tab:l}:{}}},Q=Ee.then(C);return Ee=Q.catch(()=>{}),Q}catch(t){return Promise.reject(t)}}function Ve(e){if(D(),!X.has(e))throw new Error(`未知子应用: ${e}`);const a=te.get(e);if(a)return a;let c=!0;const I=new Set([()=>{c=!1}]);B.set(e,I);async function b(o,t,r,i={}){const w=()=>{if(P)throw new u.HostCallError("HOST_DISPOSED","MicroHost 已销毁");if(r&&(r.released()||!d.tabs.some(j=>j.key===r.key)))throw new u.HostCallError("PAGE_RELEASED","页面上下文已释放");if(!c)throw new u.HostCallError("BRIDGE_RELEASED","应用 bridge 已释放")};w();const E=ve.get(o);if(!E)throw new u.HostCallError("UNKNOWN_CAPABILITY",`未注册宿主能力: ${o}`);if(E.apps&&!E.apps.has(e))throw new u.HostCallError("FORBIDDEN",`应用无权调用宿主能力: ${o}`);const S=i.timeoutMs??se;if(!Number.isFinite(S)||S<=0||S>2147483647)throw new TypeError("timeoutMs 必须为不超过2147483647的正有限数");const f=i.signal;if(f!=null&&f.aborted)throw new u.HostCallError("CANCELLED","宿主能力调用已取消");const y=new AbortController,k=r?d.tabs.find(j=>j.key===r.key):void 0,x=Object.freeze({appId:e,signal:y.signal,...k?{tab:Object.freeze({...k})}:{},isActive:()=>!y.signal.aborted&&!P&&c&&(!r||!r.released()&&d.tabs.some(j=>j.key===r.key))});return new Promise((j,H)=>{let _=!1,J;const g=()=>{J!==void 0&&clearTimeout(J),f==null||f.removeEventListener("abort",Q),I.delete(n),r==null||r.cleanups.delete(n)},C=v=>{_||(_=!0,g(),H(v),y.abort())},Q=()=>C(new u.HostCallError("CANCELLED","宿主能力调用已取消")),n=()=>{try{w()}catch(v){C(v)}};if(I.add(n),r==null||r.cleanups.add(n),f==null||f.addEventListener("abort",Q,{once:!0}),J=setTimeout(()=>C(new u.HostCallError("TIMEOUT","宿主能力调用超时")),S),f!=null&&f.aborted){Q();return}let m;try{m=E.handler(x,...t)}catch{C(new u.HostCallError("HANDLER_FAILED",`宿主能力执行失败: ${o}`));return}Promise.resolve(m).then(v=>{if(!_){try{w()}catch(F){C(F);return}_=!0,g(),j(v)}},()=>C(new u.HostCallError("HANDLER_FAILED",`宿主能力执行失败: ${o}`)))})}const h={appId:e,getState:ie,callHost(o,...t){return b(o,t)},callHostWithOptions(o,t,...r){return b(o,r,void 0,t)},protocol(){if(D(),!c)throw new Error("应用 bridge 已释放");return Object.freeze({version:"1.0",capabilities:Object.freeze([...ve].filter(([,o])=>!o.apps||o.apps.has(e)).map(([o])=>o)),features:Object.freeze(["call-options","session","event-metadata","navigate-to"])})},negotiate(o={}){const t=h.protocol(),r=Object.freeze((o.capabilities??[]).filter(i=>!t.capabilities.includes(i)));return Object.freeze({compatible:(!o.version||o.version===t.version)&&!r.length,protocol:t,missingCapabilities:r})},getSession(){if(D(),!c)throw new Error("应用 bridge 已释放");return K},subscribeSession(o){const t=h.getSession(),r=w=>o(w),i=()=>{Z.delete(r),I.delete(i)};return Z.add(r),I.add(i),U(()=>o(t)),i},subscribe(o){if(!c)throw new Error("应用 bridge 已释放");const t=ke(o),r=()=>{t(),I.delete(r)};return I.add(r),r},ready(o){const t=i=>{const w=i.tabs.find(E=>E.tabId===i.activeTabId&&E.appId===e);w&&o(w)},r=h.subscribe(t);try{t(ie())}catch(i){throw r(),i}return r},bindPage(o){const t=d.tabs.find(r=>r.tabId===o&&r.appId===e);if(!t)throw new Error("页面不属于该应用");return h.page(t.key)},page(o){if(D(),!c)throw new Error("应用 bridge 已释放");const t=d.tabs.find(f=>f.key===o&&f.appId===e);if(!t)throw new Error("页面上下文不存在或不属于该应用");let r=!1;const i=new Set,w=()=>{if(P)throw new u.NavigationError("HOST_DISPOSED","MicroHost 已销毁");if(r||!d.tabs.some(f=>f.key===o))throw new u.NavigationError("PAGE_RELEASED","页面上下文已释放")},E=()=>{var f;r=!0,i.forEach(y=>y()),i.clear(),(f=V.get(o))==null||f.delete(E)};let S=V.get(o);return S||V.set(o,S=new Set),S.add(E),{get tab(){return d.tabs.find(f=>f.key===o)??t},callHost(f,...y){return b(f,y,{key:o,released:()=>r,cleanups:i})},callHostWithOptions(f,y,...k){return b(f,k,{key:o,released:()=>r,cleanups:i},y)},async openTab(f){w();const y=await Y({type:"open",input:f},e,o,!1,()=>r);if(y.tab)return y.tab;const k=d.tabs.find(x=>x.tabId===f.tabId&&x.appId===e);if(y.status==="noop"&&k)return k;throw new u.NavigationError(y.status==="cancelled"?"CANCELLED":"STALE","导航未提交")},async navigateTo(f,y={}){return w(),Y({type:"open",input:f,signal:y.signal},e,o,!1,()=>r,!0)},async closeCurrent(){return P?!1:(await Y({type:"close",target:{tabId:t.tabId,key:o}},e,void 0,!0)).status==="committed"},beforeLeave(f){if(w(),typeof f!="function")throw new u.NavigationError("INVALID_OPERATION","离页守卫必须为函数");let y=re.get(o);y||re.set(o,y=new Set),y.add(f);const k=()=>{y.delete(f),i.delete(k)};return i.add(k),k},async refreshCurrent(){return w(),Y({type:"refresh",target:{tabId:t.tabId,key:o}},e,o,!1,()=>r)},async back(f){return w(),Y({type:"back",target:{tabId:t.tabId,key:o},fallback:f},e,o,!1,()=>r)},async operate(f){return w(),Y(f,e,o,!1,()=>r)},emit(f,y){w(),ae.emit(f,{payload:y,metadata:Object.freeze({source:"app",appId:e,tabKey:o})})},on(f,y){w();const k=de.on(f,y);return i.add(k),()=>{k(),i.delete(k)}},dispose:E}}};return te.set(e,h),h}function Be(){if(!P){P=!0;for(const e of V.values())[...e].forEach(a=>a());V.clear(),re.clear(),W.clear();for(const e of B.values())[...e].forEach(a=>a());B.clear(),ee.clear(),Z.clear(),te.clear(),de.clear(),d={tabs:[],activeTabId:null}}}return{apps:[...X.values()],getState:ie,subscribe:ke,openTab:He,activateTab:Ce,closeTab:Fe,updateTab:_e,updateSession:ze,operate:$e,bridge:Ve,bus:de,dispose:Be}}exports.createMicroHost=Ge;