From c04c7d4d8d0727f2774b3069e6a798899d1bb7c2 Mon Sep 17 00:00:00 2001 From: kdletters Date: Fri, 19 Jun 2026 07:02:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E5=8F=A3=E5=BE=AE=E4=BF=A1=E5=A3=B3?= =?UTF-8?q?=E8=83=BD=E5=8A=9B=E6=B8=85=E5=8D=95=E6=9D=A5=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 共享 HostBridge 契约新增微信小程序能力 profile 微信小程序协议测试和原生壳门禁反查共享 profile 同步宿主壳能力来源文档和共享记忆 --- .../shared-memory/decision-log.md | 8 ++++---- .../shared-memory/development-workflow.md | 1 + ...ExpoReactNative与Tauri宿主壳方案-2026-06-17.md | 4 ++-- ...前端架构】宿主壳能力统一协议-2026-06-17.md | 4 ++-- miniprogram/host-bridge/protocol.test.js | 16 ++++----------- .../shared/src/contracts/hostBridge.test.ts | 20 ++++++++++++++++--- packages/shared/src/contracts/hostBridge.ts | 7 +++++++ scripts/check-native-shells.mjs | 13 ++++++++++++ 8 files changed, 50 insertions(+), 23 deletions(-) diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index c520d7db9..7a3d21df4 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -28,7 +28,7 @@ - 2026-06-19 桌面壳系统分享 URL 边界:Tauri `share.open` 写入系统剪贴板前同样只允许把 `url`、`href`、`path`、`targetPath` 和 `work` 归一为 `https://app.genarrative.world` 同源公开 URL;外域、协议相对 URL、`javascript:` 等危险目标必须返回 `invalid_request`,且显式非法 payload 不得回退到之前缓存的 `share.setTarget` 目标。桌面壳配置检查会拒绝移除同源分享 URL 归一和协议相对 URL 拦截。 - 2026-06-18 能力声明收紧:`packages/shared/src/contracts/hostBridge.ts` 提供 HostBridge method / capability 白名单,H5 的 `getHostRuntime()` 会解析并过滤 `hostCapabilities`;`openHostShare`、`writeHostClipboardText`、`requestHostHapticsImpact`、`setHostAppTitle`、`exportHostTextFile` 等 native 能力只在宿主声明对应 capability 后调用。发布分享弹窗只有声明 `share.open` 时才显示“系统分享”,避免旧壳或裁剪壳露出不可用入口。 - 2026-06-18 宿主 runtime 回读:主 App 启动时会通过真实 `host.getRuntime` 回读 Expo / Tauri runtime 并缓存过滤后的能力清单,能力来源为 URL `hostCapabilities` 与宿主真实回包的并集;裁剪壳或旧入口 URL 缺少 `hostCapabilities` 时也能启用真实声明能力,但仍不会仅凭 `native_app` 或 transport 存在推断能力可用。 -- 2026-06-18 壳能力防漂移:`npm run mobile-shell:typecheck` 与 `npm run desktop-shell:typecheck` 会校验 Expo / Tauri 壳声明的 capability 均来自共享 HostBridge 白名单,并校验壳 runtime 回包、H5 URL `hostCapabilities` 和实现分支保持一致;微信小程序 `WECHAT_HOST_CAPABILITIES` 也由 `miniprogram/host-bridge/protocol.test.js` 反查同一共享白名单。新增能力必须先更新契约和真实壳实现,再通过这些检查。 +- 2026-06-18 壳能力防漂移:`npm run mobile-shell:typecheck` 与 `npm run desktop-shell:typecheck` 会校验 Expo / Tauri 壳声明的 capability 均来自共享 HostBridge 白名单,并校验壳 runtime 回包、H5 URL `hostCapabilities` 和实现分支保持一致;微信小程序 `WECHAT_HOST_CAPABILITIES` 由 `miniprogram/host-bridge/protocol.test.js` 和根级 `npm run check:native-shells` 反查共享 `HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES`。新增能力必须先更新契约和真实壳实现,再通过这些检查。 - 2026-06-18 原生壳统一验收门禁:根级 `npm run check:native-shells` 统一执行 H5 HostBridge 关键测试、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面 release `--no-bundle` 构建烟测,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描;根级 `npm run check` 会在 lint、主站测试、构建和内容检查后继续执行该门禁,避免 HostBridge、三端壳、Expo managed config、移动端 production bundle、桌面 release 入口和 H5 HostBridge 真实调用链禁替身验收散落成容易漏跑的单项命令。 - 2026-06-19 原生壳临时替身扫描范围:`npm run check:native-shells` 的生产替身词扫描必须覆盖微信小程序壳生产 `.js`、Expo / Tauri 壳源码与配置、共享 HostBridge 契约、H5 native transport,并自动覆盖已接入真实宿主能力 facade 的 H5 生产调用链文件;新增 H5 调用点接入 HostBridge 时,必须让自动扫描覆盖对应文件或在同等门禁中证明生产代码没有 mock / fake / stub / TODO / FIXME / 模拟 / 伪造。 - 2026-06-18 微信壳桥接层纳入统一验收:`npm run check:native-shells` 还会运行 `miniprogram/host-bridge/`、`miniprogram/shell/`、`pages/web-view` 样式和 `scripts/miniprogram-web-view-auth.test.ts` 的微信壳测试,覆盖 WebView 入口、登录触发、分享目标、支付结果、订阅消息结果和九宫切图行为;三端桥接层文件结构检查只证明目录边界,行为回归必须由同一门禁中的微信壳测试证明。 @@ -2453,9 +2453,9 @@ ## 2026-06-19 原生壳 capability profile 来源收口 - 背景:Expo 移动壳、Tauri 桌面壳和方案文档都需要维护真实 capability 子集;如果移动端源码、桌面 Rust 镜像和文档各自手写完整清单,后续新增能力时容易出现入口 URL、`host.getRuntime` 回包、文档和门禁漂移。 -- 决策:`packages/shared/src/contracts/hostBridge.ts` 中的 `HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES`、`HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES` 和 `HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES` 是原生壳 capability profile 来源。Expo 移动壳只通过 `apps/mobile-shell/src/host-bridge/capabilities.ts` 引用共享 profile 并选择平台差异;Tauri 桌面壳 `capabilities.rs` 仍保留 Rust 运行时镜像,但 `apps/desktop-shell/scripts/check-config.mjs` 和 `npm run check:native-shells` 必须反查共享桌面 profile。新增 native capability 必须先进入共享白名单和对应平台 profile,再补真实壳实现、H5 fallback、测试和文档。 -- 影响范围:`packages/shared/src/contracts/hostBridge.ts`、`apps/mobile-shell/src/host-bridge/capabilities.ts`、`apps/mobile-shell/scripts/check-config.mjs`、`apps/desktop-shell/scripts/check-config.mjs`、`scripts/check-native-shells.mjs`、Expo / Tauri HostBridge 方案文档。 -- 验证方式:`npm run check:native-shells`、`npm run mobile-shell:typecheck`、`npm run desktop-shell:typecheck`、`npm run test -- packages/shared/src/contracts/hostBridge.test.ts`、`npm run check:encoding`、`git diff --check`。 +- 决策:`packages/shared/src/contracts/hostBridge.ts` 中的 `HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES`、`HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES`、`HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES` 和 `HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES` 是三端宿主壳 capability profile 来源。Expo 移动壳只通过 `apps/mobile-shell/src/host-bridge/capabilities.ts` 引用共享 profile 并选择平台差异;微信小程序 `miniprogram/host-bridge/protocol.js` 和 Tauri 桌面壳 `capabilities.rs` 仍保留运行时镜像,但 `miniprogram/host-bridge/protocol.test.js`、`apps/desktop-shell/scripts/check-config.mjs` 和 `npm run check:native-shells` 必须反查对应共享 profile。新增 capability 必须先进入共享白名单和对应平台 profile,再补真实壳实现、H5 fallback、测试和文档。 +- 影响范围:`packages/shared/src/contracts/hostBridge.ts`、`miniprogram/host-bridge/protocol.js`、`miniprogram/host-bridge/protocol.test.js`、`apps/mobile-shell/src/host-bridge/capabilities.ts`、`apps/mobile-shell/scripts/check-config.mjs`、`apps/desktop-shell/scripts/check-config.mjs`、`scripts/check-native-shells.mjs`、HostBridge 方案文档。 +- 验证方式:`npm run check:native-shells`、`npm run mobile-shell:typecheck`、`npm run desktop-shell:typecheck`、`npm run test -- packages/shared/src/contracts/hostBridge.test.ts miniprogram/host-bridge/protocol.test.js`、`npm run check:encoding`、`git diff --check`。 ## 2026-06-18 原生壳本地生成物边界 diff --git a/docs/project-memory/shared-memory/development-workflow.md b/docs/project-memory/shared-memory/development-workflow.md index d06fd6993..d2a3d238d 100644 --- a/docs/project-memory/shared-memory/development-workflow.md +++ b/docs/project-memory/shared-memory/development-workflow.md @@ -217,6 +217,7 @@ npm run check:native-shells ``` 该命令会覆盖 H5 HostBridge 关键测试、微信 / Expo / Tauri 三端桥接层文件结构门禁、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面壳 release `--no-bundle` 构建烟测,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描,确认 Expo managed config、移动端 iOS / Android production bundle、打包 H5 资产、Tauri release 入口和 H5 HostBridge 真实调用链没有漂移;扫描范围包含微信小程序壳生产 `.js`、共享 HostBridge 契约、H5 native transport,并自动覆盖已接入真实宿主能力 facade 的 H5 生产调用链文件。壳源码和配置继续严格禁止 mock / fake / placeholder / stub / TODO / FIXME / 占位 / 模拟 / 伪造;H5 业务调用链允许正常表单 `placeholder` 属性和业务占位图文案,但仍禁止 mock / fake / stub / TODO / FIXME / 模拟 / 伪造等替身痕迹。 +该命令会反查微信小程序 `WECHAT_HOST_CAPABILITIES` 与共享 `HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES` 一致;小程序生产代码继续保留 CommonJS 运行时镜像,不直接 import TypeScript shared 包。 该命令同时会运行微信小程序 `miniprogram/host-bridge/`、`miniprogram/shell/`、`pages/web-view` 样式和 `scripts/miniprogram-web-view-auth.test.ts` 的壳层测试,保证微信桥接层拆分后的支付、订阅消息、九宫切图、分享目标和 WebView 登录 / 分享入口行为与 Expo、Tauri 壳一起验收。 该命令还会反查微信小程序 `app.json.pages` 与 `host-bridge/protocol.js` 页面 URL、H5 小程序页面常量、H5 订阅授权页面常量、WebView 分享入口、分享目标消息类型、`WEB_VIEW_SOURCE_QUERY` 和 H5 / API base URL 格式,避免页面路由、来源标记或域名配置在微信壳、H5 HostBridge 与运行时配置之间分叉。生产 / 开发 H5 与 API 域名都必须显式配置为纯 HTTPS domain,运行时开发域名回退生产域名只作为异常兜底。 diff --git a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md index d3884e207..511631012 100644 --- a/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md +++ b/docs/【前端架构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md @@ -254,7 +254,7 @@ GameBridge 禁止: - 壳层只接受来自允许 origin / packaged asset 的消息。 - H5 侧 HostBridge listener 只接收原生壳注入到当前窗口的 message;带有非当前窗口 `source` 或非当前页面 `origin` 的消息必须忽略,避免 AI sandbox iframe 或其它子上下文伪造 HostBridge response / event。 - 每个请求必须有超时;H5 的 React Native WebView transport 和 Tauri `invoke` transport 都必须在前端侧按 `timeoutMs` 释放请求,宿主侧执行超时也只能返回标准 HostBridge 错误。重复 `id` 不得重复执行支付、登录、系统分享、文件导入导出、本地通知等宿主副作用;Expo 和 Tauri 壳都必须按 request id 回放首次完成结果。 -- HostBridge 的 capability profile、文件 MIME 清单、导入 / 导出体积上限、文件名 fallback / 长度上限、request id 长度、角标上限、剪贴板文本长度、二维码文本长度和本地通知标题 / 正文长度都必须以 `packages/shared/src/contracts/hostBridge.ts` 为声明来源;Expo 移动壳直接导入共享 profile 和契约常量,Tauri 壳按 Rust 运行时代码镜像并由配置门禁反查共享契约。 +- HostBridge 的 capability profile、文件 MIME 清单、导入 / 导出体积上限、文件名 fallback / 长度上限、request id 长度、角标上限、剪贴板文本长度、二维码文本长度和本地通知标题 / 正文长度都必须以 `packages/shared/src/contracts/hostBridge.ts` 为声明来源;Expo 移动壳直接导入共享 profile 和契约常量,微信小程序壳和 Tauri 壳分别保留小程序 CommonJS / Rust 运行时代码镜像并由测试和配置门禁反查共享契约。 - 能力按 `capabilities` / `hostCapabilities` 下发,H5 会过滤未知能力,并根据声明结果决定是否展示入口、发起宿主请求或走 fallback;进入 `native_app` 后主 App 会再通过真实 `host.getRuntime` 回读一次宿主 runtime 并缓存能力,用来补齐裁剪壳或旧入口 URL 缺少 `hostCapabilities` 的场景。不能只凭 `native_app` 宿主类型假设能力可用。 - 壳能力声明与三端壳验收必须通过 `npm run check:native-shells` 统一校验;排查单端问题时可再分别运行微信壳测试集合、`npm run mobile-shell:typecheck`、`npm run mobile-shell:test`、`npm run mobile-shell:config`、`npm run mobile-shell:export`、`npm run desktop-shell:typecheck`、`npm run desktop-shell:test` 或 `npm run desktop-shell:build -- --no-bundle`。声明的 capability 必须来自共享 HostBridge profile 并存在于共享白名单,壳 runtime 回包、H5 URL `hostCapabilities`、壳实现、文件载荷边界、微信 WebView / 支付 / 订阅 / 分享桥接行为、微信小程序页面路由、WebView source query、微信壳 H5 / API HTTPS 域名格式、Expo managed config、移动端 production bundle、桌面 release 构建入口和微信 / Expo / Tauri 三端生产源码临时替身词扫描不得漂移。 - Expo SDK、React Native、`react-native-webview`、Tauri CLI、Tauri Rust crate 和桌面 Cargo 插件版本属于宿主壳行为边界。升级这些依赖前必须同步更新壳配置检查、`package-lock.json` / `Cargo.lock` 解析版本、本文档和对应验证结果,不能只改 package / Cargo 版本让生产壳行为静默漂移。 @@ -296,7 +296,7 @@ GameBridge 禁止: 2026-06-19 追加:移动壳声明并实现 `scanner.scanQrCode`,通过 `expo-camera` 请求系统相机权限并用 `CameraView` 扫描二维码。扫码控制器一次只允许一个进行中的请求,成功结果复用共享 `normalizeHostBridgeQrCodeValue` 边界,只回传清洗后的二维码文本和 `qr_code` 格式;用户关闭返回 `cancelled`,H5 个人中心扫码入口不会在取消后继续弹出浏览器摄像头权限。宿主缺能力、旧壳 unsupported 或返回非法结果时,H5 继续打开原浏览器扫码弹层。Tauri 桌面壳只保留 method 白名单并返回 `unsupported_method`,不声明桌面扫码 capability。 -2026-06-19 追加:移动壳 iOS 额外真实能力为 `app.setBadgeCount`。`packages/shared/src/contracts/hostBridge.ts` 中的 `HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES`、`HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES` 和 `HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES` 是原生壳能力 profile 来源;移动壳直接引用共享 profile,桌面壳 Rust 清单作为运行时镜像并由配置检查反查同一共享 profile。`npm run check:native-shells` 会从共享 profile 反查能力清单文档和桌面 Rust 镜像,避免实现、入口 URL 和方案文档再次漂移。 +2026-06-19 追加:微信小程序壳真实能力 profile 为 `HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES`,当前只包含 `auth.requestLogin`、`payment.request`、`share.setTarget` 和 `share.open`;`miniprogram/host-bridge/protocol.js` 继续保留 `WECHAT_HOST_CAPABILITIES` 作为小程序运行时镜像,不直接 import TypeScript shared 包,`miniprogram/host-bridge/protocol.test.js` 和根级 `npm run check:native-shells` 必须反查它与共享微信 profile 完全一致。移动壳 iOS 额外真实能力为 `app.setBadgeCount`。`packages/shared/src/contracts/hostBridge.ts` 中的 `HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES`、`HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES`、`HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES` 和 `HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES` 是三端宿主能力 profile 来源;移动壳直接引用共享 profile,微信小程序壳和桌面壳分别以运行时镜像承接并由门禁反查同一共享 profile。`npm run check:native-shells` 会从共享 profile 反查能力清单文档、小程序协议镜像和桌面 Rust 镜像,避免实现、入口 URL 和方案文档再次漂移。 2026-06-18 追加:移动壳 `navigation.canGoBack` 不再只读取 `react-native-webview` 的原生跨文档导航状态。Expo 壳会在 WebView `injectedJavaScriptBeforeContentLoaded` 中注入固定脚本,追踪当前 H5 文档内 `pushState` / `replaceState` / `popstate` 写入的路由栈,并通过内部 `genarrative.mobile.historyState` 消息回传;壳层把原生 WebView back-forward 状态与 H5 当前文档路由栈状态合成为 HostBridge `navigation.canGoBack` 事件。Android 返回键优先执行固定 `window.history.back(); true;` 回退 H5 SPA 路由,只有 H5 当前文档不可回退时才调用 WebView 原生 `goBack()`;该内部消息不是 HostBridge request method,也不开放 H5 到原生的通用事件写入通道。 diff --git a/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md b/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md index 722ec01e0..375cea2f3 100644 --- a/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md +++ b/docs/【前端架构】宿主壳能力统一协议-2026-06-17.md @@ -79,7 +79,7 @@ HostBridge 事件名以 `packages/shared/src/contracts/hostBridge.ts` 的 `HOST_ 2. `authService` 保留原导出,但内部委托 HostBridge,避免一次性改动 AuthGate。 3. 分享弹窗、分享目标同步、九宫切图、微信小程序支付和订阅授权改用 HostBridge 通用接口;旧微信命名服务只作为兼容导出。 4. 后续新增 `native_app` adapter 时只补桥接实现和测试,业务层不新增平台分叉;主 App 启动会触发一次 `host.getRuntime` 回读并订阅能力变化,避免裁剪壳或旧入口 URL 缺少 `hostCapabilities` 时长期隐藏真实可用能力。 -5. 每次新增或调整 native capability / HostBridge event 后,必须先更新 `packages/shared/src/contracts/hostBridge.ts` 中对应 Expo / Tauri capability profile 和事件白名单,再运行 `npm run check:native-shells`,统一覆盖 H5 HostBridge 关键测试、三端桥接层文件结构门禁、微信小程序页面路由与 H5 常量反查、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面 release `--no-bundle` 构建烟测,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描;排查单端问题时再单独运行 `npm run mobile-shell:typecheck`、`npm run mobile-shell:test`、`npm run mobile-shell:config`、`npm run mobile-shell:export`、`npm run desktop-shell:typecheck`、`npm run desktop-shell:test` 或 `npm run desktop-shell:build -- --no-bundle`。 +5. 每次新增或调整 native capability / HostBridge event 后,必须先更新 `packages/shared/src/contracts/hostBridge.ts` 中对应微信 / Expo / Tauri capability profile 和事件白名单,再运行 `npm run check:native-shells`,统一覆盖 H5 HostBridge 关键测试、三端桥接层文件结构门禁、微信小程序页面路由与 H5 常量反查、Expo 壳 typecheck / test / config smoke / Metro export smoke、Tauri 壳 typecheck / cargo test、桌面 release `--no-bundle` 构建烟测,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描;排查单端问题时再单独运行 `npm run mobile-shell:typecheck`、`npm run mobile-shell:test`、`npm run mobile-shell:config`、`npm run mobile-shell:export`、`npm run desktop-shell:typecheck`、`npm run desktop-shell:test` 或 `npm run desktop-shell:build -- --no-bundle`。 ## 验收 @@ -88,7 +88,7 @@ HostBridge 事件名以 `packages/shared/src/contracts/hostBridge.ts` 的 `HOST_ - 小程序支付仍跳转 `/pages/wechat-pay/index` 并保留支付结果 hash 回灌确认。 - 小程序订阅授权仍跳转 `/pages/subscribe-message/index`,且返回不阻断生成主链路。 - 普通浏览器分享、H5 支付和 Native 二维码支付不受影响。 -- 原生壳统一验收入口 `npm run check:native-shells` 通过,能力白名单、共享 capability profile、HostBridge event 白名单、壳 runtime 回包、URL `hostCapabilities`、H5 fallback、微信小程序 `app.json.pages` 与 `protocol.js` 页面 URL、H5 小程序页面常量、H5 订阅授权页面常量、WebView 分享入口、分享目标消息类型、WebView source query、生产 / 开发 H5 与 API HTTPS 域名格式、三端桥接层结构、两端壳实现、Expo managed config、移动端 production bundle、桌面 release 构建入口,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描没有漂移;扫描范围包含微信小程序壳生产 `.js`、共享 HostBridge 契约、H5 native transport,并自动覆盖已接入真实宿主能力 facade 的 H5 生产调用链文件。H5 业务文件允许正常表单 `placeholder` 属性和业务占位图文案,但不得出现 mock / fake / stub / TODO / FIXME / 模拟 / 伪造等替身痕迹。 +- 原生壳统一验收入口 `npm run check:native-shells` 通过,能力白名单、微信 / Expo / Tauri 共享 capability profile、HostBridge event 白名单、壳 runtime 回包、URL `hostCapabilities`、H5 fallback、微信小程序 `app.json.pages` 与 `protocol.js` 页面 URL、H5 小程序页面常量、H5 订阅授权页面常量、WebView 分享入口、分享目标消息类型、WebView source query、生产 / 开发 H5 与 API HTTPS 域名格式、三端桥接层结构、两端壳实现、Expo managed config、移动端 production bundle、桌面 release 构建入口,以及可分发壳与 H5 HostBridge 真实调用链的临时替身词扫描没有漂移;扫描范围包含微信小程序壳生产 `.js`、共享 HostBridge 契约、H5 native transport,并自动覆盖已接入真实宿主能力 facade 的 H5 生产调用链文件。H5 业务文件允许正常表单 `placeholder` 属性和业务占位图文案,但不得出现 mock / fake / stub / TODO / FIXME / 模拟 / 伪造等替身痕迹。 ## 后续 diff --git a/miniprogram/host-bridge/protocol.test.js b/miniprogram/host-bridge/protocol.test.js index f43dac2b6..6bf38f87e 100644 --- a/miniprogram/host-bridge/protocol.test.js +++ b/miniprogram/host-bridge/protocol.test.js @@ -2,7 +2,7 @@ import path from 'node:path'; import { describe, expect, test } from 'vitest'; -import { HOST_BRIDGE_CAPABILITIES } from '../../packages/shared/src/contracts/hostBridge.ts'; +import { HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES } from '../../packages/shared/src/contracts/hostBridge.ts'; import { loadCommonJsModule } from '../test-utils/loadCommonJsModule.js'; const protocolPath = path.resolve( @@ -34,17 +34,9 @@ describe('wechat mini program host bridge protocol index', () => { test('keeps native page routes and result keys centralized', () => { const protocol = loadCommonJsModule(protocolPath); - expect(protocol.WECHAT_HOST_CAPABILITIES).toEqual([ - 'auth.requestLogin', - 'payment.request', - 'share.setTarget', - 'share.open', - ]); - expect( - protocol.WECHAT_HOST_CAPABILITIES.filter( - (capability) => !HOST_BRIDGE_CAPABILITIES.includes(capability), - ), - ).toEqual([]); + expect(protocol.WECHAT_HOST_CAPABILITIES).toEqual( + HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES, + ); expect(protocol.WECHAT_AUTH_PAGE_URL).toBe( '/pages/web-view/index?authAction=login&returnTo=previous', ); diff --git a/packages/shared/src/contracts/hostBridge.test.ts b/packages/shared/src/contracts/hostBridge.test.ts index 38079701f..8ec0c79b6 100644 --- a/packages/shared/src/contracts/hostBridge.test.ts +++ b/packages/shared/src/contracts/hostBridge.test.ts @@ -5,6 +5,7 @@ import { HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES, HOST_BRIDGE_EXPO_MOBILE_IOS_EXTRA_CAPABILITIES, HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES, + HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES, HOST_BRIDGE_PUBLIC_WEB_ORIGIN, HOST_BRIDGE_PUBLIC_WEB_URL, HOST_BRIDGE_TAURI_COMMAND, @@ -116,8 +117,9 @@ describe('HostBridge shared contract helpers', () => { expect(isHostBridgeEventName(null)).toBe(false); }); - test('原生壳 capability profile 来自共享白名单', () => { + test('宿主壳 capability profile 来自共享白名单', () => { const profiles = [ + HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES, HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES, HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES, HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES, @@ -126,8 +128,20 @@ describe('HostBridge shared contract helpers', () => { expect(profile.every((capability) => HOST_BRIDGE_CAPABILITIES.includes(capability), )).toBe(true); - expect(profile).not.toContain('auth.requestLogin'); - expect(profile).not.toContain('payment.request'); + } + expect(HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES).toEqual([ + 'auth.requestLogin', + 'payment.request', + 'share.setTarget', + 'share.open', + ]); + for (const nativeAppProfile of [ + HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES, + HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES, + HOST_BRIDGE_TAURI_DESKTOP_CAPABILITIES, + ]) { + expect(nativeAppProfile).not.toContain('auth.requestLogin'); + expect(nativeAppProfile).not.toContain('payment.request'); } }); diff --git a/packages/shared/src/contracts/hostBridge.ts b/packages/shared/src/contracts/hostBridge.ts index d73d423d2..9ce1273d6 100644 --- a/packages/shared/src/contracts/hostBridge.ts +++ b/packages/shared/src/contracts/hostBridge.ts @@ -72,6 +72,13 @@ export function isHostBridgeCapability( ); } +export const HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES: readonly HostBridgeCapability[] = [ + 'auth.requestLogin', + 'payment.request', + 'share.setTarget', + 'share.open', +]; + export const HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES: readonly HostBridgeCapability[] = [ 'host.getRuntime', 'appearance.getColorScheme', diff --git a/scripts/check-native-shells.mjs b/scripts/check-native-shells.mjs index 2e7add264..a0bac5282 100644 --- a/scripts/check-native-shells.mjs +++ b/scripts/check-native-shells.mjs @@ -739,6 +739,10 @@ function assertNativeShellCapabilityPlan() { const sharedContractSource = fs.readFileSync(sharedHostBridgeContractPath, 'utf8'); const sharedMethods = extractTsStringArray(sharedContractSource, 'HOST_BRIDGE_METHODS'); const sharedEvents = extractTsStringArray(sharedContractSource, 'HOST_BRIDGE_EVENTS'); + const sharedWechatCapabilities = extractTsStringArray( + sharedContractSource, + 'HOST_BRIDGE_WECHAT_MINI_PROGRAM_CAPABILITIES', + ); const mobileCapabilities = extractTsStringArray( sharedContractSource, 'HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES', @@ -759,6 +763,15 @@ function assertNativeShellCapabilityPlan() { 'apps/desktop-shell/src-tauri/src/shell/events.rs', 'utf8', ); + const wechatProtocol = requireCommonJsModule( + 'miniprogram/host-bridge/protocol.js', + ); + + assertSameList( + wechatProtocol.WECHAT_HOST_CAPABILITIES ?? [], + sharedWechatCapabilities, + 'wechat mini program runtime capability profile', + ); assertSameList( extractRustStringArray(desktopEventSource, 'HOST_BRIDGE_EVENTS'),