@fulgurjs/federation 5.4.0 → 5.4.2
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/CHANGELOG.md +8 -0
- package/README.en.md +6 -4
- package/README.md +15 -10
- package/dist/bridge-app-react.d.cts +1 -1
- package/dist/bridge-app-react.d.ts +1 -1
- package/dist/bridge-app-react.js +1 -1
- package/dist/bridge-app-vue.d.cts +1 -1
- package/dist/bridge-app-vue.d.ts +1 -1
- package/dist/bridge-app-vue.js +1 -1
- package/dist/{bridge-core-BOWvVUxO.d.ts → bridge-core-ejlY9ddN.d.ts} +3 -1
- package/dist/bridge-core.d.cts +1 -1
- package/dist/bridge-core.d.ts +1 -1
- package/dist/bridge-core.js +2 -2
- package/dist/bridge-errors.cjs +5 -4
- package/dist/bridge-errors.d.cts +1 -1
- package/dist/bridge-errors.d.ts +1 -1
- package/dist/bridge-errors.js +1 -1
- package/dist/{bridge-host-react-CMVd-ym0.d.ts → bridge-host-react-Bua1TCVh.d.ts} +1 -1
- package/dist/bridge-host-react.cjs +54 -45
- package/dist/bridge-host-react.d.cts +1 -1
- package/dist/bridge-host-react.d.ts +1 -1
- package/dist/bridge-host-react.js +3 -3
- package/dist/{bridge-host-vue-BuCGlLdS.d.ts → bridge-host-vue-Dd1kkwDb.d.ts} +1 -1
- package/dist/bridge-host-vue.cjs +54 -45
- package/dist/bridge-host-vue.js +3 -3
- package/dist/bridge-react.d.ts +4 -4
- package/dist/{bridge-router-core-BxBx-reP.d.ts → bridge-router-core-BRZQYDPm.d.cts} +3 -1
- package/dist/{bridge-router-core-BxBx-reP.d.cts → bridge-router-core-BRZQYDPm.d.ts} +3 -1
- package/dist/bridge-router-react.d.ts +25 -42
- package/dist/bridge-router-react.js +213 -36
- package/dist/bridge-router-vue.d.ts +18 -37
- package/dist/bridge-router-vue.js +188 -44
- package/dist/bridge-vue.d.ts +2 -2
- package/dist/bridge.d.ts +5 -5
- package/dist/{chunk-GF6KOH67.js → chunk-43UX3UZE.js} +1 -1
- package/dist/{chunk-WOTR2FUQ.js → chunk-7CQOVLSI.js} +50 -42
- package/dist/{chunk-JQF7KYZF.js → chunk-HZGQOW35.js} +5 -4
- package/dist/{chunk-OXEAGRPY.js → chunk-KT3YARK5.js} +1 -1
- package/dist/{chunk-PRUYHYX2.js → chunk-RXXBTPAY.js} +1 -1
- package/dist/{chunk-BTJGYDHT.js → chunk-UFWZPE36.js} +55 -55
- package/dist/index.cjs +42 -10
- package/dist/index.js +42 -10
- package/dist/runtime.js +9 -9
- package/examples/bridge/react-host/package-lock.json +13 -5
- package/examples/bridge/react-host/package.json +1 -1
- package/examples/bridge/react-remote/package-lock.json +13 -5
- package/examples/bridge/react-remote/package.json +1 -1
- package/examples/bridge/vue-host/package-lock.json +13 -5
- package/examples/bridge/vue-host/package.json +1 -1
- package/examples/bridge/vue-remote/package-lock.json +13 -5
- package/examples/bridge/vue-remote/package.json +1 -1
- package/examples/react/host/package-lock.json +13 -4
- package/examples/react/host/package.json +1 -1
- package/examples/react/remote/package-lock.json +13 -4
- package/examples/react/remote/package.json +1 -1
- package/examples/vue/host/package-lock.json +13 -4
- package/examples/vue/host/package.json +1 -1
- package/examples/vue/remote/package-lock.json +13 -4
- package/examples/vue/remote/package.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.4.1
|
|
4
|
+
|
|
5
|
+
- 修复 URL 同步两端适配器将 replace 误报为 push、子应用 go/back/forward 未委托宿主历史,以及连续导航被丢弃的问题。
|
|
6
|
+
- React 宿主等待真实 blocker 的 reset/proceed 与提交位置;canNavigate 改为可选预判。Vue 初始 ready 和导航执行异常不再吞掉,MFU-033 保留 cause,队列失败后可继续导航。
|
|
7
|
+
- 修复 Vite 5/6 配套 plugin-react 4 的跨框架 dev preamble 标志缺失,避免 Vue 宿主加载 React 远程失败;子目录部署示例的 blocker 按逻辑路径判断。
|
|
8
|
+
- 修复 React 18 + RR6 生产渲染的跨共享键 CJS 双实例:提供闭包只豁免自引用,react-dom → react 走同步协商;入口 init 前的同步副本复用现有 fallback 回写规则登记,避免 renderer 与组件使用不同 React。
|
|
9
|
+
- 通道离页、暂停与卸载会作废在飞和排队请求;自定义宿主 navigate 可接收 AbortSignal;子应用接线可传 ctx.signal 自动清理。Vue history base 不再二次剥离;前缀与目标拒绝编码逃逸。
|
|
10
|
+
|
|
3
11
|
## 5.4.0
|
|
4
12
|
|
|
5
13
|
- **新增:跨框架桥接 URL 同步(`/bridge/router/*`)**——宿主 URL 表达子应用内部位置:首次深链直达(不闪默认页、不发错接口)、刷新/收藏/新窗口恢复、子应用 Link/RouterLink/router.push 与宿主菜单/前进后退全量同步、根重定向以 replace 规范化(不凭空制造历史)。架构:宿主 Router 是浏览器历史唯一写入方,子应用用受控 memory 路由(Vue `connectVueBridgeRouter` / React `createReactBridgeRouter`,Link/useNavigate/RouterLink 全兼容);独立路由通道承载位置与仲裁(请求编号/代次隔离/外部作废/取消恢复),path/search/hash 三段原样保留(重复键/编码/中文/片段不二次转换),同实例路径变化**不重挂 root、不重建 store、不重载远程**。
|
package/README.en.md
CHANGED
|
@@ -53,7 +53,7 @@ pnpm add -D @fulgurjs/federation
|
|
|
53
53
|
- Vue ≥ 3.2.0 and/or React `>=18.0.0 <20` — all three are **optional peers**; install only the framework you use
|
|
54
54
|
- Chrome 108+ (native top-level await)
|
|
55
55
|
|
|
56
|
-
> Vite 8 (rolldown): as of 5.3.3, dev, production builds and production page mounting all pass full acceptance (bidirectional bridge 11-step interaction matrix, see the acceptance report). The first page open on a cold dev cache still falls inside the dependency pre-bundling window (DEV-010; it self-recovers via reload). Warm up before acceptance runs or manual judgement, as documented.
|
|
56
|
+
> Vite 8 (rolldown): as of 5.3.3, dev, production builds and production page mounting all pass full acceptance (bidirectional bridge 11-step interaction matrix, see the acceptance report). **5.4.2 boundary note**: in production builds of large apps (e.g. JeecgBoot v3.9.5), the plugin's TLA share facades joining chunk merging can trigger a rolldown codegen bug that merges the app's own async initialization into a sync lazy init and drops the `async` marker (`SyntaxError: Unexpected reserved word`; minify/target/manualChunks variants and a bare-baseline comparison have ruled out other variables) — build such apps for production with Vite 5–7; dev is unaffected. The first page open on a cold dev cache still falls inside the dependency pre-bundling window (DEV-010; it self-recovers via reload). Warm up before acceptance runs or manual judgement, as documented.
|
|
57
57
|
|
|
58
58
|
`@fulgurjs/federation/runtime` and `@fulgurjs/federation/react` are **ESM-only** browser entries (no `require()`). The build-time main entry supports both ESM and CJS.
|
|
59
59
|
|
|
@@ -343,13 +343,15 @@ The bridge defaults to memory routing: internal navigation does not touch the br
|
|
|
343
343
|
|
|
344
344
|
**Architecture**: the host router is the only writer of browser history; the sub-app uses a controlled memory router; both sides communicate over a dedicated routing channel (not appProps/Context); path/search/hash changes within an instance **do not remount the root, do not rebuild stores, do not reload the remote**.
|
|
345
345
|
|
|
346
|
-
**Host (Vue Router 4, history or hash mode)**: declare a suffix route (`/approval/:pathMatch(.*)*` — without it detail navigation unmounts the sub-app), add real guards (`beforeEach` rejecting → the channel receives `cancelled`, URL/history/sub-app position unchanged), then `createVueBridgeNavigation(router
|
|
346
|
+
**Host (Vue Router 4, history or hash mode)**: declare a suffix route (`/approval/:pathMatch(.*)*` — without it detail navigation unmounts the sub-app), add real guards (`beforeEach` rejecting → the channel receives `cancelled`, URL/history/sub-app position unchanged), then `createVueBridgeNavigation(router)` (Vue Router already removes its history base) and pass `routing={{ basePath: '/approval', navigation }}` to the bridge component.
|
|
347
347
|
|
|
348
348
|
**Sub-app**: declare the protocol and wire a controlled router —
|
|
349
349
|
Vue: `defineBridgeApp(async (props, ctx) => { const router = createRouter({ history: createMemoryHistory(), routes }); await connectVueBridgeRouter(ctx.routing!, router).ready; ... app.use(router); return app }, { routing: true })` (await ready BEFORE `app.use(router)` — the install-time initial navigation would otherwise override the deep-link location).
|
|
350
350
|
React: `createReactBridgeRouter(ctx.routing!, routes).element` — `createMemoryRouter`-based; `Link`/`useNavigate` work unmodified.
|
|
351
351
|
|
|
352
|
-
**Host (React Router)**: data routers only (`createBrowserRouter`/`createHashRouter` + `RouterProvider`); `createReactBridgeNavigation(router, { basename, canNavigate })`.
|
|
352
|
+
**Host (React Router)**: data routers only (`createBrowserRouter`/`createHashRouter` + `RouterProvider`); `createReactBridgeNavigation(router, { basename, canNavigate })`. `canNavigate` is an optional early rejection policy. The adapter also observes the real blocker: it waits for `reset()` (cancelled) or a committed navigation after `proceed()`. Resolving `router.navigate()` alone does not imply a commit. Declarative `BrowserRouter` has no cancellation semantics and is not supported. Requires react-router ≥ 6.11.
|
|
353
|
+
|
|
354
|
+
**Lifecycle and navigation**: both child connectors accept an optional third argument `{ signal?: AbortSignal }`; pass `ctx.signal` to dispose on session invalidation, or call `connection.dispose()` yourself. Push and replace retain their history action; numeric navigation delegates to the host history. Concurrent requests are serialized and superseded requests are invalidated. Navigation errors reject with MFU-033 and preserve `cause`; they are not reported as cancellation. Custom host ports receive an optional third argument `{ signal }` and must check it before asynchronous commits.
|
|
353
355
|
|
|
354
356
|
**Contract highlights**: `basePath` is a static absolute path from the host-router perspective (segment-matched; conflicting/overlapping prefixes rejected, `MFU-030`); location is compared and preserved as three raw strings (duplicate query keys, encoding, fragments survive without re-encoding); cancellation never auto-retries; session switch (`sessionKey→null`) invalidates the old channel — late navigations are rejected and never write the URL; KeepAlive-cached instances pause routing writes; enabling sync against a contract without `{ routing: true }` shows `MFU-031` instead of silently falling back to memory; escaping targets and illegal `go` arguments → `MFU-032`; redirect loops beyond 5 internal replaces → `MFU-033` with the chain attached. Router libraries are optional peers consumed only through the two opt-in entries (`/bridge/router/vue`, `/bridge/router/react`, each gated ≤ 4096B gzip); the default entries never load a router library. Not promised: SSR/RSC, cross-window, nested multi-level bridge routing proxies, TanStack Router and other libraries (extend via the `BridgeHostNavigation`/`BridgeChildRoute` ports).
|
|
355
357
|
|
|
@@ -420,7 +422,7 @@ Lazy-loading measurement layers: ① nothing until first render of a remote comp
|
|
|
420
422
|
| MFU | `MFU-030` | Bridge URL-sync config invalid / prefix conflict (illegal basePath: empty, root, query/hash/wildcard; overlapping active prefixes) |
|
|
421
423
|
| MFU | `MFU-031` | Bridge routing protocol missing / channel destroyed (sub-app not declared with `{ routing: true }`; disposed channel reused) |
|
|
422
424
|
| MFU | `MFU-032` | Bridge illegal navigation (target escaping its own prefix, illegal `go` argument, request on a dead channel) |
|
|
423
|
-
| MFU | `MFU-033` | Bridge routing sync failed (
|
|
425
|
+
| MFU | `MFU-033` | Bridge routing preparation/sync failed (redirect limit or navigation exception, chain/cause attached; no silent fallback to memory) |
|
|
424
426
|
| CC | `CC-001` | AppContext required key missing (got/expected/example) |
|
|
425
427
|
| | `CC-002` | runtime singleton unavailable (standalone remote page) |
|
|
426
428
|
|
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ pnpm add -D @fulgurjs/federation
|
|
|
51
51
|
|
|
52
52
|
要求:Vite ≥ 5.1(实测至 8.x)、Node ≥ 18、Vue 3 和/或 React 18–19(均为可选 peer——按所用框架安装)、浏览器 Chrome 108+(TLA 原生支持)。
|
|
53
53
|
|
|
54
|
-
> Vite 8(rolldown):5.3.3 起 dev 与生产构建、生产页面挂载均已通过完整验收(双向桥接 11
|
|
54
|
+
> Vite 8(rolldown):5.3.3 起 dev 与生产构建、生产页面挂载均已通过完整验收(双向桥接 11 步交互矩阵,见验收报告)。**5.4.2 补充边界**:大型应用(如 JeecgBoot v3.9.5)生产构建下,插件的 TLA 共享门面参与 chunk 合并时可触发 rolldown 将应用 async 初始化语句合并丢 `async` 标记(`SyntaxError: Unexpected reserved word`,minify/target/manualChunks 变体与裸基线对照已排除其他变量)——此类应用生产构建请用 Vite 5–7,开发态不受影响。dev 冷启动首开仍受依赖预构建窗口影响(DEV-010,首轮打开自动恢复),验收与人工判断请按文档先预热。
|
|
55
55
|
|
|
56
56
|
## 快速开始(React 应用)
|
|
57
57
|
|
|
@@ -663,7 +663,7 @@ CLI 解析同一份配置值;dev/prod 的 URL 选择规则与 `federation({ re
|
|
|
663
663
|
| | `MFU-030` | 桥接路由同步配置/前缀冲突(basePath 非法:空/根/带 query·hash·通配、同页重叠前缀登记) |
|
|
664
664
|
| | `MFU-031` | 桥接路由协议缺失/通道失效(子应用未以 `{ routing: true }` 声明协议、通道销毁后复用) |
|
|
665
665
|
| | `MFU-032` | 桥接非法导航(子应用导航目标越界自身前缀、`go` 参数非法、失效通道的请求被拒绝) |
|
|
666
|
-
| | `MFU-033` |
|
|
666
|
+
| | `MFU-033` | 桥接路由准备/同步失败(重定向超限或导航异常,附目标链/cause;不静默回退 memory) |
|
|
667
667
|
| CC 跨应用上下文 | `CC-001` | AppContext 必需字段缺失(三段式:got/expected/example,修法指向宿主桥 `provideAppContext`) |
|
|
668
668
|
| | `CC-002` | 运行时单例不可用(独立直开远程页;修法 = 经宿主联邦加载,时序契约 bridge → 远程 setup → 页面模块) |
|
|
669
669
|
|
|
@@ -903,7 +903,7 @@ router.beforeEach((to) => (to.path.startsWith('/approval/secret') ? false : unde
|
|
|
903
903
|
<script setup lang="ts">
|
|
904
904
|
import { createVueBridgeApp } from '@fulgurjs/federation/bridge/vue'
|
|
905
905
|
import { createVueBridgeNavigation, type BridgeHostRouting } from '@fulgurjs/federation/bridge/router/vue'
|
|
906
|
-
const navigation = createVueBridgeNavigation(router) //
|
|
906
|
+
const navigation = createVueBridgeNavigation(router) // Vue Router fullPath 已是逻辑路径,无需传部署 base
|
|
907
907
|
const routing: BridgeHostRouting = { basePath: '/approval', navigation }
|
|
908
908
|
const RemoteApp = createVueBridgeApp('remote/bridge-routed', { /* 同 8.2 */ })
|
|
909
909
|
</script>
|
|
@@ -920,11 +920,12 @@ import { createRouter, createMemoryHistory, RouterView } from 'vue-router'
|
|
|
920
920
|
import { defineBridgeApp } from '@fulgurjs/federation/runtime'
|
|
921
921
|
import { connectVueBridgeRouter } from '@fulgurjs/federation/bridge/router/vue'
|
|
922
922
|
export default defineBridgeApp(async (props, ctx) => {
|
|
923
|
+
if (!ctx?.routing) throw new Error('本契约需要宿主启用 URL 同步')
|
|
923
924
|
const router = createRouter({ history: createMemoryHistory(), routes: [
|
|
924
925
|
{ path: '/list', component: List },
|
|
925
926
|
{ path: '/detail/:id', component: Detail },
|
|
926
927
|
] })
|
|
927
|
-
await connectVueBridgeRouter(ctx.routing!, router).ready // 初始 push 落定后再 install(顺序不能反)
|
|
928
|
+
await connectVueBridgeRouter(ctx.routing!, router, { signal: ctx.signal }).ready // 初始 push 落定后再 install(顺序不能反)
|
|
928
929
|
const app = createApp({ setup: () => () => h(RouterView) }, props)
|
|
929
930
|
app.use(router)
|
|
930
931
|
return app
|
|
@@ -934,21 +935,25 @@ export default defineBridgeApp(async (props, ctx) => {
|
|
|
934
935
|
```tsx
|
|
935
936
|
// bridge.tsx(React 子应用):createReactBridgeRouter 返回 RouterProvider 元素
|
|
936
937
|
import { createReactBridgeRouter } from '@fulgurjs/federation/bridge/router/react'
|
|
937
|
-
|
|
938
|
-
|
|
938
|
+
import { defineBridgeApp } from '@fulgurjs/federation/react'
|
|
939
|
+
export default defineBridgeApp((_props, ctx) => {
|
|
940
|
+
if (!ctx?.routing) throw new Error('本契约需要宿主启用 URL 同步')
|
|
941
|
+
return createReactBridgeRouter(ctx.routing, [
|
|
939
942
|
{ path: '/list', element: <List /> },
|
|
940
943
|
{ path: '/detail/:id', element: <Detail /> },
|
|
941
|
-
]
|
|
944
|
+
], { signal: ctx.signal }).element
|
|
945
|
+
}, { routing: true })
|
|
942
946
|
```
|
|
943
947
|
|
|
944
|
-
宿主端 React Router 仅支持 **data router 模式**(`createBrowserRouter` / `createHashRouter` + `RouterProvider`):`createReactBridgeNavigation(router, { basename, canNavigate })`。`canNavigate`
|
|
948
|
+
宿主端 React Router 仅支持 **data router 模式**(`createBrowserRouter` / `createHashRouter` + `RouterProvider`):`createReactBridgeNavigation(router, { basename, canNavigate })`。`canNavigate` 可选,仅作提前拒绝;端口观察真实 `useBlocker` 状态,等待 `reset()` 返回 cancelled、`proceed()` 后实际位置提交返回 committed,不能只凭 navigate 的 Promise 落定判成功。declarative 模式(BrowserRouter)无取消语义,不支持。React Router 要求 ≥ 6.11(createMemoryRouter)。
|
|
945
949
|
|
|
946
950
|
**③ 行为契约与边界**:
|
|
947
951
|
|
|
948
952
|
- **basePath**:宿主路由视角的静态绝对路径(拒绝空/根/带 query·hash·通配符,`MFU-030`);按路径段匹配(`/approval` 命中 `/approval/detail/1`,不命中 `/approval-old`);同页各同步实例前缀不得相同或重叠。`/approval` 对应子应用 `/`;根重定向由子应用路由定义、以 replace 规范化(不凭空多一条历史)。
|
|
949
|
-
- **Vite base 与路由分层**:部署在 `/erp/` 时 Vite base/宿主 Router base 是 `/erp/`,bridge basePath 仍是 `/approval`(Vue
|
|
953
|
+
- **Vite base 与路由分层**:部署在 `/erp/` 时 Vite base/宿主 Router base 是 `/erp/`,bridge basePath 仍是 `/approval`(Vue Router 已自动剥离 history base,React 端口传 `basename`);适配器输出的逻辑路径不含部署前缀,不会拼出 `/erp/erp/...`。子目录部署 + hash 模式内层片段见 e2e fixtures(`fixtures/host-bridge-*/`,可运行参考实现)。
|
|
950
954
|
- **位置三段全等**:search/hash 原样保留(重复 query 键、编码、中文、片段不二次 decode/encode);仅参数变化也同步,且不重挂。
|
|
951
|
-
- **取消语义**:Vue Router 4 的 push/replace 落定 `NavigationFailure` 即真实取消;React Router data router
|
|
955
|
+
- **取消语义**:Vue Router 4 的 push/replace 落定 `NavigationFailure` 即真实取消;React Router data router 等待真实 blocker 的取消/放行,`canNavigate` 仅为可选提前拒绝。取消后 URL、历史、子应用位置保持最后确认状态,**绝不自动重试**(`router.push` 的函数返回不冒充提交成功)。
|
|
956
|
+
- **导航与错误**:子应用 push/replace 保留原动作,go/back/forward 委托宿主历史;连续请求串行落定,外部导航作废旧的在飞与排队请求。守卫/加载器/端口执行异常拒绝 Promise(MFU-033,保留 cause),不会伪装 cancelled。两端子路由接线的第三参数 `{ signal?: AbortSignal }` 默认为空;推荐传 `ctx.signal` 自动 dispose,未传时由子应用显式调用连接的 `dispose()`。自定义 `BridgeHostNavigation.navigate(target, action, { signal })` 应在异步提交前复核可选 signal,已 aborted 时禁止迟到写入。
|
|
952
957
|
- **会话与生命周期**:换账号/登出(`sessionKey→null`)作废旧通道——旧通道的导航一律 cancelled、不写 URL、不复活子应用;unmount 后迟到通知失效(通道销毁,再订阅得 `MFU-031`)。KeepAlive 缓存离页的实例暂停路由写入(不抢占 URL、不销毁通道,激活重同步)。同一容器 unmount 抛错的持久封锁(BN09)不因路由绕过。
|
|
953
958
|
- **协议校验**:宿主启用 routing 而子应用未声明 `{ routing: true }`(契约 `routing: { protocol: 1 }`)→ `MFU-031` 占位,**不静默退回 memory 假装深链成功**。
|
|
954
959
|
- **非法导航与循环**:目标越界自身前缀(`../`、跨前缀)、非法 `go` 参数 → `MFU-032`;连续内部 replace 超过 5 次(重定向环)→ `MFU-033`(附目标链,不静默回入口)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { BridgeApp } from './bridge-core.cjs';
|
|
3
|
-
import { B as BridgeChildRoute } from './bridge-router-core-
|
|
3
|
+
import { B as BridgeChildRoute } from './bridge-router-core-BRZQYDPm.cjs';
|
|
4
4
|
import './context.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
2
|
import { BridgeApp } from './bridge-core.js';
|
|
3
|
-
import { B as BridgeChildRoute } from './bridge-router-core-
|
|
3
|
+
import { B as BridgeChildRoute } from './bridge-router-core-BRZQYDPm.js';
|
|
4
4
|
import './context.js';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/bridge-app-react.js
CHANGED
package/dist/bridge-app-vue.d.ts
CHANGED
package/dist/bridge-app-vue.js
CHANGED
|
@@ -15,7 +15,9 @@ type BridgeNavigationResult = {
|
|
|
15
15
|
interface BridgeHostNavigation {
|
|
16
16
|
getLocation(): BridgeLocation;
|
|
17
17
|
subscribe(listener: (location: BridgeLocation) => void): () => void;
|
|
18
|
-
navigate(target: BridgeLocation, action: 'push' | 'replace'
|
|
18
|
+
navigate(target: BridgeLocation, action: 'push' | 'replace', options?: {
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
}): Promise<BridgeNavigationResult>;
|
|
19
21
|
go(delta: number): void;
|
|
20
22
|
}
|
|
21
23
|
/** 子应用路由通道(桥接宿主按挂载代次创建,随 mount 第三参数交给子应用) */
|
package/dist/bridge-core.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AppContext } from './context.cjs';
|
|
2
|
-
import { a as BridgeMountOptions, b as BridgeRoutingProtocol } from './bridge-router-core-
|
|
2
|
+
import { a as BridgeMountOptions, b as BridgeRoutingProtocol } from './bridge-router-core-BRZQYDPm.cjs';
|
|
3
3
|
|
|
4
4
|
/** 子应用桥接契约(远程 ./bridge 模块的默认导出;任务书 §3.2) */
|
|
5
5
|
interface BridgeApp {
|
package/dist/bridge-core.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AppContext } from './context.js';
|
|
2
|
-
import { a as BridgeMountOptions, b as BridgeRoutingProtocol } from './bridge-router-core-
|
|
2
|
+
import { a as BridgeMountOptions, b as BridgeRoutingProtocol } from './bridge-router-core-BRZQYDPm.js';
|
|
3
3
|
|
|
4
4
|
/** 子应用桥接契约(远程 ./bridge 模块的默认导出;任务书 §3.2) */
|
|
5
5
|
interface BridgeApp {
|
package/dist/bridge-core.js
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
releaseBridgeSession,
|
|
7
7
|
resolveBridgeContext,
|
|
8
8
|
withBridgeTimeout
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-RXXBTPAY.js";
|
|
10
|
+
import "./chunk-HZGQOW35.js";
|
|
11
11
|
import "./chunk-TSYLDY6H.js";
|
|
12
12
|
import "./chunk-OF2JCXTZ.js";
|
|
13
13
|
export {
|
package/dist/bridge-errors.cjs
CHANGED
|
@@ -143,13 +143,14 @@ function routingNavigationError(spec, reason) {
|
|
|
143
143
|
{ spec }
|
|
144
144
|
);
|
|
145
145
|
}
|
|
146
|
-
function routingSyncError(spec, reason, chain) {
|
|
146
|
+
function routingSyncError(spec, reason, chain, cause) {
|
|
147
147
|
return new FgError(
|
|
148
148
|
BridgeErrorCodes.ROUTING_SYNC_FAILED,
|
|
149
|
-
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 URL \u540C\u6B65\
|
|
149
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 URL \u540C\u6B65\u5931\u8D25\u3002
|
|
150
150
|
\u539F\u56E0\uFF1A${reason}
|
|
151
|
-
\u4FEE\u6CD5\uFF1A\u68C0\u67E5\
|
|
152
|
-
{ spec, chain: [...chain] }
|
|
151
|
+
\u4FEE\u6CD5\uFF1A\u68C0\u67E5\u8DEF\u7531\u5B88\u536B\u3001\u52A0\u8F7D\u5668\u4E0E\u5BFC\u822A\u5F02\u5E38\uFF1B\u91CD\u5B9A\u5411\u94FE\u4E0D\u5E94\u6210\u73AF\u3002\u76EE\u6807\u94FE\uFF1A${chain.join(" \u2192 ")}\u3002`,
|
|
152
|
+
{ spec, chain: [...chain] },
|
|
153
|
+
{ cause }
|
|
153
154
|
);
|
|
154
155
|
}
|
|
155
156
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/bridge-errors.d.cts
CHANGED
|
@@ -47,6 +47,6 @@ declare function routingProtocolError(spec: string, reason: string): FgError;
|
|
|
47
47
|
/** MFU-032:非法导航(越界目标、非法 go 参数、失效通道请求被拒绝) */
|
|
48
48
|
declare function routingNavigationError(spec: string, reason: string): FgError;
|
|
49
49
|
/** MFU-033:路由准备/同步失败(重定向循环等;不伪装成功也不静默回退 memory) */
|
|
50
|
-
declare function routingSyncError(spec: string, reason: string, chain: string[]): FgError;
|
|
50
|
+
declare function routingSyncError(spec: string, reason: string, chain: string[], cause?: unknown): FgError;
|
|
51
51
|
|
|
52
52
|
export { BridgeErrorCodes, type BridgePhase, bridgeLifecycleError, bridgeSessionMismatchError, invalidBridgeContractError, invalidSessionKeyError, routingConfigError, routingNavigationError, routingProtocolError, routingSyncError };
|
package/dist/bridge-errors.d.ts
CHANGED
|
@@ -47,6 +47,6 @@ declare function routingProtocolError(spec: string, reason: string): FgError;
|
|
|
47
47
|
/** MFU-032:非法导航(越界目标、非法 go 参数、失效通道请求被拒绝) */
|
|
48
48
|
declare function routingNavigationError(spec: string, reason: string): FgError;
|
|
49
49
|
/** MFU-033:路由准备/同步失败(重定向循环等;不伪装成功也不静默回退 memory) */
|
|
50
|
-
declare function routingSyncError(spec: string, reason: string, chain: string[]): FgError;
|
|
50
|
+
declare function routingSyncError(spec: string, reason: string, chain: string[], cause?: unknown): FgError;
|
|
51
51
|
|
|
52
52
|
export { BridgeErrorCodes, type BridgePhase, bridgeLifecycleError, bridgeSessionMismatchError, invalidBridgeContractError, invalidSessionKeyError, routingConfigError, routingNavigationError, routingProtocolError, routingSyncError };
|
package/dist/bridge-errors.js
CHANGED
|
@@ -169,13 +169,14 @@ function routingNavigationError(spec, reason) {
|
|
|
169
169
|
{ spec }
|
|
170
170
|
);
|
|
171
171
|
}
|
|
172
|
-
function routingSyncError(spec, reason, chain) {
|
|
172
|
+
function routingSyncError(spec, reason, chain, cause) {
|
|
173
173
|
return new FgError(
|
|
174
174
|
BridgeErrorCodes.ROUTING_SYNC_FAILED,
|
|
175
|
-
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 URL \u540C\u6B65\
|
|
175
|
+
`\u73B0\u8C61\uFF1A\u6865\u63A5\u5E94\u7528 "${spec}" \u7684 URL \u540C\u6B65\u5931\u8D25\u3002
|
|
176
176
|
\u539F\u56E0\uFF1A${reason}
|
|
177
|
-
\u4FEE\u6CD5\uFF1A\u68C0\u67E5\
|
|
178
|
-
{ spec, chain: [...chain] }
|
|
177
|
+
\u4FEE\u6CD5\uFF1A\u68C0\u67E5\u8DEF\u7531\u5B88\u536B\u3001\u52A0\u8F7D\u5668\u4E0E\u5BFC\u822A\u5F02\u5E38\uFF1B\u91CD\u5B9A\u5411\u94FE\u4E0D\u5E94\u6210\u73AF\u3002\u76EE\u6807\u94FE\uFF1A${chain.join(" \u2192 ")}\u3002`,
|
|
178
|
+
{ spec, chain: [...chain] },
|
|
179
|
+
{ cause }
|
|
179
180
|
);
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -288,10 +289,11 @@ var MAX_GO_DELTA = 50;
|
|
|
288
289
|
function normalizeBasePath(basePath, spec) {
|
|
289
290
|
const bad = (reason) => routingConfigError(spec, reason);
|
|
290
291
|
if (typeof basePath !== "string" || basePath === "") throw bad("basePath \u4E0D\u80FD\u4E3A\u7A7A\u3002");
|
|
291
|
-
if (basePath
|
|
292
|
+
if (/^\/+$/u.test(basePath)) throw bad('basePath \u4E0D\u80FD\u662F\u6839 "/"\u2014\u2014\u6839\u8DEF\u5F84\u5C5E\u4E8E\u5BBF\u4E3B\u81EA\u8EAB\u9875\u9762\uFF0C\u8BF7\u4E3A\u540C\u6B65\u5B9E\u4F8B\u5206\u914D\u72EC\u7ACB\u524D\u7F00\u3002');
|
|
292
293
|
if (!basePath.startsWith("/")) throw bad(`basePath \u5FC5\u987B\u4EE5 "/" \u5F00\u5934\uFF1A\u5F53\u524D\u4E3A "${basePath}"\u3002`);
|
|
293
294
|
if (/[?#]/.test(basePath) || basePath.includes("://")) throw bad(`basePath \u4E0D\u80FD\u5305\u542B query/hash/\u534F\u8BAE\uFF1A\u5F53\u524D\u4E3A "${basePath}"\u3002`);
|
|
294
295
|
if (basePath.includes("*") || basePath.includes(":")) throw bad(`basePath \u4E0D\u63A5\u53D7\u901A\u914D\u7B26\u6216\u53C2\u6570\u6A21\u677F\uFF1A\u5F53\u524D\u4E3A "${basePath}"\u3002\u8BF7\u4F7F\u7528\u9759\u6001\u7EDD\u5BF9\u8DEF\u5F84\u3002`);
|
|
296
|
+
if (/\\|\/\/|%(?:2e|2f|5c)/i.test(basePath) || basePath.split("/").some((part) => part === "." || part === "..")) throw bad("basePath \u4E0D\u80FD\u5305\u542B\u7A7A\u8DEF\u5F84\u6BB5\u3001\u8F6C\u4E49\u5206\u9694\u7B26\u6216\u76F8\u5BF9\u8DEF\u5F84\u6BB5\u3002");
|
|
295
297
|
return basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
|
|
296
298
|
}
|
|
297
299
|
function matchesBasePath(hostPathname, basePath) {
|
|
@@ -315,7 +317,8 @@ function sameLocation(a, b) {
|
|
|
315
317
|
return a.pathname === b.pathname && a.search === b.search && a.hash === b.hash;
|
|
316
318
|
}
|
|
317
319
|
function assertChildTargetInScope(target, basePath, spec) {
|
|
318
|
-
if (target.pathname.
|
|
320
|
+
if (!target || typeof target.pathname !== "string" || typeof target.search !== "string" || typeof target.hash !== "string" || target.search !== "" && !target.search.startsWith("?") || target.hash !== "" && !target.hash.startsWith("#")) throw routingNavigationError(spec, "\u5BFC\u822A\u76EE\u6807\u5FC5\u987B\u63D0\u4F9B pathname\u3001search\u3001hash \u4E09\u6BB5\uFF0Csearch/hash \u5E94\u4E3A\u7A7A\u6216\u4EE5 ?/# \u5F00\u5934\u3002");
|
|
321
|
+
if (/[\x00-\x20\\?#]|%(?:2e|2f|5c)/i.test(target.pathname) || target.pathname.includes("//") || target.pathname.split("/").some((part) => part === "." || part === "..")) {
|
|
319
322
|
throw routingNavigationError(spec, `\u5BFC\u822A\u76EE\u6807\u8BD5\u56FE\u9003\u9038\u81EA\u8EAB\u524D\u7F00\uFF1Apathname "${target.pathname}"\u3002\u8DE8\u524D\u7F00\u5BFC\u822A\u8BF7\u901A\u8FC7\u5BBF\u4E3B\u83DC\u5355\u7B49\u5BBF\u4E3B\u80FD\u529B\u5B8C\u6210\u3002`);
|
|
320
323
|
}
|
|
321
324
|
const host = toHostLocation(target, basePath, spec);
|
|
@@ -357,6 +360,8 @@ var RoutingChannel = class {
|
|
|
357
360
|
lastConfirmed;
|
|
358
361
|
seq = 0;
|
|
359
362
|
inflight = null;
|
|
363
|
+
queue;
|
|
364
|
+
generation = 0;
|
|
360
365
|
disposed = false;
|
|
361
366
|
active = true;
|
|
362
367
|
releasePrefix;
|
|
@@ -371,7 +376,8 @@ var RoutingChannel = class {
|
|
|
371
376
|
this.spec = spec;
|
|
372
377
|
this.basePath = normalizeBasePath(basePath, spec);
|
|
373
378
|
this.host = host;
|
|
374
|
-
|
|
379
|
+
const initial = host.getLocation();
|
|
380
|
+
this.current = matchesBasePath(initial.pathname, this.basePath) ? toChildLocation(initial, this.basePath) : { pathname: "/", search: "", hash: "" };
|
|
375
381
|
this.lastConfirmed = { ...this.current };
|
|
376
382
|
this.releasePrefix = acquireRoutingPrefix(this.basePath, spec);
|
|
377
383
|
this.unsubHost = host.subscribe((loc) => this.handleHostLocation(loc));
|
|
@@ -389,6 +395,7 @@ var RoutingChannel = class {
|
|
|
389
395
|
handleHostLocation(hostLoc) {
|
|
390
396
|
if (this.disposed) return;
|
|
391
397
|
if (!matchesBasePath(hostLoc.pathname, this.basePath)) {
|
|
398
|
+
this.cancelPending();
|
|
392
399
|
this.onEvent?.({ type: "prefix-miss", pathname: hostLoc.pathname });
|
|
393
400
|
return;
|
|
394
401
|
}
|
|
@@ -398,23 +405,21 @@ var RoutingChannel = class {
|
|
|
398
405
|
}
|
|
399
406
|
const child = toChildLocation(hostLoc, this.basePath);
|
|
400
407
|
if (this.inflight && sameLocation(child, this.inflight.target)) {
|
|
401
|
-
const { seq
|
|
402
|
-
this.inflight = null;
|
|
408
|
+
const { seq } = this.inflight;
|
|
403
409
|
this.lastConfirmed = child;
|
|
404
410
|
this.emit(child);
|
|
405
411
|
this.onEvent?.({ type: "request-confirmed", seq });
|
|
406
|
-
resolve({ status: "committed", location: { ...child } });
|
|
407
412
|
return;
|
|
408
413
|
}
|
|
409
414
|
if (this.inflight) {
|
|
410
|
-
const
|
|
411
|
-
this.inflight = null;
|
|
415
|
+
const seq = this.inflight.seq;
|
|
412
416
|
this.lastConfirmed = child;
|
|
417
|
+
this.cancelPending();
|
|
413
418
|
this.emit(child);
|
|
414
419
|
this.onEvent?.({ type: "request-superseded", seq });
|
|
415
|
-
resolve({ status: "cancelled", location: { ...child } });
|
|
416
420
|
return;
|
|
417
421
|
}
|
|
422
|
+
if (!sameLocation(child, this.lastConfirmed)) this.generation++;
|
|
418
423
|
this.lastConfirmed = child;
|
|
419
424
|
this.emit(child);
|
|
420
425
|
this.onEvent?.({ type: "host-broadcast" });
|
|
@@ -431,8 +436,31 @@ var RoutingChannel = class {
|
|
|
431
436
|
this.listeners.delete(listener);
|
|
432
437
|
};
|
|
433
438
|
}
|
|
434
|
-
|
|
435
|
-
|
|
439
|
+
cancelPending() {
|
|
440
|
+
this.generation++;
|
|
441
|
+
const pending = this.inflight;
|
|
442
|
+
this.inflight = null;
|
|
443
|
+
if (pending) {
|
|
444
|
+
pending.abort.abort();
|
|
445
|
+
pending.resolve({ status: "cancelled", location: { ...this.lastConfirmed } });
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
navigate(target, action) {
|
|
449
|
+
const generation = this.generation;
|
|
450
|
+
const snapshot = { ...target };
|
|
451
|
+
const run = () => generation !== this.generation ? Promise.resolve({ status: "cancelled", location: { ...this.lastConfirmed } }) : this.performNavigation(snapshot, action);
|
|
452
|
+
const task = this.queue ? this.queue.then(run) : run();
|
|
453
|
+
const tail = task.then(() => {
|
|
454
|
+
}, () => {
|
|
455
|
+
});
|
|
456
|
+
this.queue = tail;
|
|
457
|
+
void tail.then(() => {
|
|
458
|
+
if (this.queue === tail) this.queue = void 0;
|
|
459
|
+
});
|
|
460
|
+
return task;
|
|
461
|
+
}
|
|
462
|
+
async performNavigation(target, action) {
|
|
463
|
+
if (this.disposed || !this.active || !matchesBasePath(this.host.getLocation().pathname, this.basePath)) {
|
|
436
464
|
this.onEvent?.({ type: this.disposed ? "rejected-disposed" : "rejected-inactive" });
|
|
437
465
|
return { status: "cancelled", location: { ...this.lastConfirmed } };
|
|
438
466
|
}
|
|
@@ -455,28 +483,12 @@ var RoutingChannel = class {
|
|
|
455
483
|
this.redirectChain = [];
|
|
456
484
|
throw routingSyncError(this.spec, "\u540C\u4E00\u901A\u9053\u7684\u8FDE\u7EED replace \u91CD\u5B9A\u5411\u8D85\u8FC7\u4E0A\u9650\uFF08\u7591\u4F3C\u5B50\u5E94\u7528\u8DEF\u7531\u4E92\u76F8\u6210\u73AF\uFF09\u3002", chain);
|
|
457
485
|
}
|
|
458
|
-
if (this.inflight) {
|
|
459
|
-
const prev = this.inflight;
|
|
460
|
-
await new Promise((resolve) => {
|
|
461
|
-
const timer = setInterval(() => {
|
|
462
|
-
if (this.inflight !== prev) {
|
|
463
|
-
clearInterval(timer);
|
|
464
|
-
resolve();
|
|
465
|
-
}
|
|
466
|
-
}, 0);
|
|
467
|
-
});
|
|
468
|
-
if (this.disposed || !this.active) {
|
|
469
|
-
return { status: "cancelled", location: { ...this.lastConfirmed } };
|
|
470
|
-
}
|
|
471
|
-
if (sameLocation(target, this.lastConfirmed)) {
|
|
472
|
-
return { status: "committed", location: { ...this.lastConfirmed } };
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
486
|
const seq = ++this.seq;
|
|
476
487
|
this.onEvent?.({ type: "request-start", seq, target: { ...target }, action });
|
|
477
|
-
return new Promise((resolve) => {
|
|
478
|
-
|
|
479
|
-
this.
|
|
488
|
+
return new Promise((resolve, reject) => {
|
|
489
|
+
const abort = new AbortController();
|
|
490
|
+
this.inflight = { seq, target: { ...target }, resolve, abort };
|
|
491
|
+
Promise.resolve().then(() => abort.signal.aborted ? { status: "cancelled", location: this.host.getLocation() } : this.host.navigate(toHostLocation(target, this.basePath, this.spec), action, { signal: abort.signal })).then((result) => {
|
|
480
492
|
if (!this.inflight || this.inflight.seq !== seq) return;
|
|
481
493
|
if (this.disposed || !this.active) {
|
|
482
494
|
this.inflight = null;
|
|
@@ -484,7 +496,7 @@ var RoutingChannel = class {
|
|
|
484
496
|
return;
|
|
485
497
|
}
|
|
486
498
|
this.inflight = null;
|
|
487
|
-
if (result.status === "committed") {
|
|
499
|
+
if (result.status === "committed" && matchesBasePath(result.location.pathname, this.basePath)) {
|
|
488
500
|
const child = toChildLocation(result.location, this.basePath);
|
|
489
501
|
this.lastConfirmed = child;
|
|
490
502
|
this.emit(child);
|
|
@@ -493,21 +505,21 @@ var RoutingChannel = class {
|
|
|
493
505
|
}
|
|
494
506
|
this.onEvent?.({ type: "host-verdict", seq, status: result.status });
|
|
495
507
|
resolve(
|
|
496
|
-
result.status === "committed" ? { status: "committed", location: { ...this.lastConfirmed } } : { status: "cancelled", location: { ...this.lastConfirmed } }
|
|
508
|
+
result.status === "committed" && matchesBasePath(result.location.pathname, this.basePath) ? { status: "committed", location: { ...this.lastConfirmed } } : { status: "cancelled", location: { ...this.lastConfirmed } }
|
|
497
509
|
);
|
|
498
|
-
}).catch(() => {
|
|
510
|
+
}).catch((cause) => {
|
|
499
511
|
if (this.inflight?.seq === seq) {
|
|
500
512
|
this.inflight = null;
|
|
501
513
|
this.onEvent?.({ type: "host-error", seq });
|
|
502
514
|
this.emit({ ...this.lastConfirmed });
|
|
503
|
-
|
|
515
|
+
reject(routingSyncError(this.spec, `\u5BBF\u4E3B\u5BFC\u822A\u6267\u884C\u5931\u8D25\uFF1A${cause instanceof Error ? cause.message : String(cause)}`, [], cause));
|
|
504
516
|
}
|
|
505
517
|
});
|
|
506
518
|
});
|
|
507
519
|
}
|
|
508
520
|
/** 委托宿主历史(有限整数);不创建第二条独立历史 */
|
|
509
521
|
go(delta) {
|
|
510
|
-
if (this.disposed || !this.active) return;
|
|
522
|
+
if (this.disposed || !this.active || !matchesBasePath(this.host.getLocation().pathname, this.basePath)) return;
|
|
511
523
|
if (typeof delta !== "number" || !Number.isInteger(delta) || Math.abs(delta) > MAX_GO_DELTA) {
|
|
512
524
|
throw routingNavigationError(this.spec, `go \u53C2\u6570\u5FC5\u987B\u662F\u6709\u9650\u6574\u6570\uFF08|delta| \u2264 ${MAX_GO_DELTA}\uFF09\uFF1A\u5F53\u524D\u4E3A ${String(delta)}\u3002`);
|
|
513
525
|
}
|
|
@@ -516,6 +528,7 @@ var RoutingChannel = class {
|
|
|
516
528
|
/** KeepAlive deactivate:暂停广播与写入;通道与订阅保留(activate 后 resync) */
|
|
517
529
|
setActive(active) {
|
|
518
530
|
if (this.disposed) return;
|
|
531
|
+
if (!active) this.cancelPending();
|
|
519
532
|
this.active = active;
|
|
520
533
|
this.onEvent?.({ type: active ? "resumed" : "paused" });
|
|
521
534
|
if (active) this.handleHostLocation(this.host.getLocation());
|
|
@@ -527,11 +540,7 @@ var RoutingChannel = class {
|
|
|
527
540
|
if (this.redirectTimer) clearTimeout(this.redirectTimer);
|
|
528
541
|
this.unsubHost();
|
|
529
542
|
this.releasePrefix();
|
|
530
|
-
|
|
531
|
-
const { resolve } = this.inflight;
|
|
532
|
-
this.inflight = null;
|
|
533
|
-
resolve({ status: "cancelled", location: { ...this.lastConfirmed } });
|
|
534
|
-
}
|
|
543
|
+
this.cancelPending();
|
|
535
544
|
this.listeners.clear();
|
|
536
545
|
this.onEvent?.({ type: "disposed" });
|
|
537
546
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode, ComponentType } from 'react';
|
|
2
2
|
import { AppContext } from './context.cjs';
|
|
3
|
-
import { c as BridgeHostRouting } from './bridge-router-core-
|
|
3
|
+
import { c as BridgeHostRouting } from './bridge-router-core-BRZQYDPm.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* React 宿主桥接工厂(/bridge、/bridge/react 导出 createReactBridgeApp;任务书 §3.4)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode, ComponentType } from 'react';
|
|
2
2
|
import { AppContext } from './context.js';
|
|
3
|
-
import { c as BridgeHostRouting } from './bridge-router-core-
|
|
3
|
+
import { c as BridgeHostRouting } from './bridge-router-core-BRZQYDPm.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* React 宿主桥接工厂(/bridge、/bridge/react 导出 createReactBridgeApp;任务书 §3.4)。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RoutingChannel,
|
|
3
3
|
assertBridgeRoutingProtocol
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-7CQOVLSI.js";
|
|
5
5
|
import {
|
|
6
6
|
acquireBridgeSession,
|
|
7
7
|
assertBridgeContract,
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
releaseBridgeSession,
|
|
11
11
|
resolveBridgeContext,
|
|
12
12
|
withBridgeTimeout
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-RXXBTPAY.js";
|
|
14
14
|
import {
|
|
15
15
|
bridgeLifecycleError
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-HZGQOW35.js";
|
|
17
17
|
import {
|
|
18
18
|
provideAppContext
|
|
19
19
|
} from "./chunk-TSYLDY6H.js";
|