@skillbuilder/miniapp-simulator 0.0.0-stage → 0.2.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 (229) hide show
  1. package/README.md +263 -2
  2. package/assets/phones/Nexus-5X.png +0 -0
  3. package/assets/phones/iPhone-14ProMax.png +0 -0
  4. package/assets/rednote-preview/cover/homebar-1439.jpg +0 -0
  5. package/assets/rednote-preview/cover/homebar-1679.jpg +0 -0
  6. package/assets/rednote-preview/cover/homebar-1919.jpg +0 -0
  7. package/assets/rednote-preview/cover/homebar-2284.jpg +0 -0
  8. package/assets/rednote-preview/cover/homebar-2285.jpg +0 -0
  9. package/assets/rednote-preview/cover/like.png +0 -0
  10. package/assets/rednote-preview/cover/play.png +0 -0
  11. package/assets/rednote-preview/cover/topbar-1439.jpg +0 -0
  12. package/assets/rednote-preview/cover/topbar-1679.jpg +0 -0
  13. package/assets/rednote-preview/cover/topbar-1919.jpg +0 -0
  14. package/assets/rednote-preview/cover/topbar-2284.jpg +0 -0
  15. package/assets/rednote-preview/cover/topbar-2285.jpg +0 -0
  16. package/assets/workbench/index.html +77 -0
  17. package/dist/sw/miniapp-simulator-service-worker.js +971 -0
  18. package/dist/sw/miniapp-simulator-service-worker.min.js +1 -0
  19. package/docs/consumer-guide.md +143 -0
  20. package/docs/electron-review.md +21 -0
  21. package/docs/external-cli-workbench.md +195 -0
  22. package/docs/file-system-design.md +334 -0
  23. package/docs/host-external-api.md +235 -0
  24. package/docs/iframe-service-worker.md +190 -0
  25. package/docs/local-dev.md +106 -0
  26. package/docs/npm-integration-verification.md +35 -0
  27. package/docs/remote-architecture.md +404 -0
  28. package/docs/remote-load-observability.md +268 -0
  29. package/docs/remote-usage.md +371 -0
  30. package/docs/request-design.md +247 -0
  31. package/docs/sdk-usage.md +260 -0
  32. package/docs/server-playground-https-debugging.md +150 -0
  33. package/docs/storage-api-design.md +275 -0
  34. package/docs/tracker.md +339 -0
  35. package/docs/worker-runtime.md +62 -0
  36. package/lib/business-line-CMb3ehRn.mjs +15 -0
  37. package/lib/client-CO-UjIY3.mjs +775 -0
  38. package/lib/index-B5oixYXr.mjs +574 -0
  39. package/lib/index.js +10763 -0
  40. package/lib/preload/webview-preload.js +37 -0
  41. package/lib/remote-client.js +11 -0
  42. package/lib/types/business-line.d.ts +7 -0
  43. package/lib/types/capabilities/constants.d.ts +29 -0
  44. package/lib/types/capabilities/csp-snippet.d.ts +34 -0
  45. package/lib/types/capabilities/launch-options.d.ts +7 -0
  46. package/lib/types/capabilities/performance-policy.d.ts +5 -0
  47. package/lib/types/capabilities/security-head-snippet.d.ts +21 -0
  48. package/lib/types/capabilities/security.d.ts +25 -0
  49. package/lib/types/capabilities/style-snippet.d.ts +2 -0
  50. package/lib/types/core/controllers/game-playtest.d.ts +9 -0
  51. package/lib/types/core/controllers/gesture.d.ts +8 -0
  52. package/lib/types/core/controllers/host-api.d.ts +19 -0
  53. package/lib/types/core/controllers/index.d.ts +11 -0
  54. package/lib/types/core/controllers/inspector.d.ts +20 -0
  55. package/lib/types/core/controllers/note-preview.d.ts +9 -0
  56. package/lib/types/core/controllers/permission-sheet.d.ts +7 -0
  57. package/lib/types/core/controllers/widget-cover.d.ts +12 -0
  58. package/lib/types/core/lifecycle.d.ts +7 -0
  59. package/lib/types/core/options.d.ts +33 -0
  60. package/lib/types/core/simulator.d.ts +9 -0
  61. package/lib/types/errors.d.ts +11 -0
  62. package/lib/types/event-bus.d.ts +15 -0
  63. package/lib/types/gesture/host-bus.d.ts +113 -0
  64. package/lib/types/gesture/index.d.ts +27 -0
  65. package/lib/types/gesture/plugins/double-tap.d.ts +10 -0
  66. package/lib/types/gesture/plugins/index.d.ts +27 -0
  67. package/lib/types/gesture/plugins/long-press.d.ts +13 -0
  68. package/lib/types/gesture/plugins/multi-touch-hint.d.ts +11 -0
  69. package/lib/types/gesture/plugins/multi-touch-switch.d.ts +18 -0
  70. package/lib/types/gesture/plugins/selection-disabler.d.ts +11 -0
  71. package/lib/types/gesture/plugins/tap.d.ts +11 -0
  72. package/lib/types/gesture/plugins/touch-emitter.d.ts +11 -0
  73. package/lib/types/gesture/plugins/wheel-scroll.d.ts +11 -0
  74. package/lib/types/gesture/receiver-runtime.d.ts +10 -0
  75. package/lib/types/gesture/receiver-runtime.impl.d.ts +6 -0
  76. package/lib/types/gesture/touch-cursor.d.ts +78 -0
  77. package/lib/types/gesture/touch-dot.d.ts +12 -0
  78. package/lib/types/gesture/types.d.ts +206 -0
  79. package/lib/types/host/shadow-host.d.ts +40 -0
  80. package/lib/types/index.d.ts +56 -0
  81. package/lib/types/injection/guest-log-mark.d.ts +7 -0
  82. package/lib/types/injection/head-builder.d.ts +4 -0
  83. package/lib/types/injection/index.d.ts +19 -0
  84. package/lib/types/injection/modules/console-forward.d.ts +2 -0
  85. package/lib/types/injection/modules/gesture.d.ts +6 -0
  86. package/lib/types/injection/modules/inspector-guest-runtime.d.ts +5 -0
  87. package/lib/types/injection/modules/inspector-pause-runtime.d.ts +6 -0
  88. package/lib/types/injection/modules/inspector.d.ts +8 -0
  89. package/lib/types/injection/modules/jsapi-channel.d.ts +9 -0
  90. package/lib/types/injection/modules/jsapi.d.ts +22 -0
  91. package/lib/types/injection/modules/render-done.d.ts +2 -0
  92. package/lib/types/injection/modules/resource-guard.d.ts +7 -0
  93. package/lib/types/injection/modules/scroll-containment.d.ts +3 -0
  94. package/lib/types/injection/modules/security.d.ts +3 -0
  95. package/lib/types/injection/modules/widget-snapshot.d.ts +13 -0
  96. package/lib/types/injection/preload-builder.d.ts +41 -0
  97. package/lib/types/injection/registry.d.ts +20 -0
  98. package/lib/types/injection/types.d.ts +45 -0
  99. package/lib/types/inspector/host-inspector.d.ts +108 -0
  100. package/lib/types/inspector/index.d.ts +8 -0
  101. package/lib/types/inspector/selector.d.ts +18 -0
  102. package/lib/types/native-ui/devtools/CapabilitiesView.d.ts +18 -0
  103. package/lib/types/native-ui/devtools/DevtoolsPanel.d.ts +24 -0
  104. package/lib/types/native-ui/devtools/LogsView.d.ts +17 -0
  105. package/lib/types/native-ui/devtools/dom.d.ts +40 -0
  106. package/lib/types/native-ui/devtools/index.d.ts +19 -0
  107. package/lib/types/native-ui/devtools/log-entry.d.ts +8 -0
  108. package/lib/types/native-ui/devtools/shortcut.d.ts +12 -0
  109. package/lib/types/native-ui/devtools/tokens.d.ts +14 -0
  110. package/lib/types/native-ui/devtools/types.d.ts +51 -0
  111. package/lib/types/native-ui/index.d.ts +17 -0
  112. package/lib/types/native-ui/note-publish/defaults.d.ts +40 -0
  113. package/lib/types/native-ui/note-publish/index.d.ts +2 -0
  114. package/lib/types/native-ui/note-publish/miniapp-note-publish.d.ts +15 -0
  115. package/lib/types/native-ui/note-publish/note-publish-host.d.ts +15 -0
  116. package/lib/types/native-ui/note-publish/view-data.d.ts +21 -0
  117. package/lib/types/native-ui/permission-sheet/defaults.d.ts +12 -0
  118. package/lib/types/native-ui/permission-sheet/index.d.ts +4 -0
  119. package/lib/types/native-ui/permission-sheet/miniapp-permission-sheet.d.ts +19 -0
  120. package/lib/types/native-ui/permission-sheet/permission-sheet-host.d.ts +23 -0
  121. package/lib/types/native-ui/permission-sheet/types.d.ts +8 -0
  122. package/lib/types/native-ui/rednote-preview/chrome-tone.d.ts +44 -0
  123. package/lib/types/native-ui/rednote-preview/defaults.d.ts +30 -0
  124. package/lib/types/native-ui/rednote-preview/half-sheet-drag.d.ts +61 -0
  125. package/lib/types/native-ui/rednote-preview/index.d.ts +2 -0
  126. package/lib/types/native-ui/rednote-preview/register.d.ts +7 -0
  127. package/lib/types/native-ui/rednote-preview/styles.d.ts +4 -0
  128. package/lib/types/native-ui/rednote-preview/xhs-note-detail-shell.d.ts +70 -0
  129. package/lib/types/native-ui/rednote-preview/xhs-note-half-sheet.d.ts +100 -0
  130. package/lib/types/native-ui/rednote-preview/xhs-profile-shell.d.ts +31 -0
  131. package/lib/types/native-ui/toast/frame-toast-host.d.ts +18 -0
  132. package/lib/types/native-ui/toast/index.d.ts +19 -0
  133. package/lib/types/presets.d.ts +11 -0
  134. package/lib/types/remote/client.d.ts +89 -0
  135. package/lib/types/remote/jsapi-config.d.ts +9 -0
  136. package/lib/types/remote/load-timing.d.ts +46 -0
  137. package/lib/types/remote/protocol.d.ts +165 -0
  138. package/lib/types/remote/review-launch.d.ts +6 -0
  139. package/lib/types/remote/runtime-entry.d.ts +1 -0
  140. package/lib/types/remote/runtime.d.ts +14 -0
  141. package/lib/types/remote/simulator-prompt.d.ts +9 -0
  142. package/lib/types/remote/widget-snapshot-guest-runtime.d.ts +1 -0
  143. package/lib/types/remote-client.d.ts +5 -0
  144. package/lib/types/renderer/base.d.ts +8 -0
  145. package/lib/types/renderer/content-host/iframe-content-host.d.ts +84 -0
  146. package/lib/types/renderer/content-host/index.d.ts +3 -0
  147. package/lib/types/renderer/content-host/types.d.ts +89 -0
  148. package/lib/types/renderer/content-host/webview-content-host.d.ts +53 -0
  149. package/lib/types/renderer/iframe.d.ts +93 -0
  150. package/lib/types/renderer/index.d.ts +2 -0
  151. package/lib/types/renderer/rednote-shell.d.ts +73 -0
  152. package/lib/types/renderer/webview.d.ts +59 -0
  153. package/lib/types/runtime/context.d.ts +31 -0
  154. package/lib/types/runtime/jsapi-modules/context.d.ts +19 -0
  155. package/lib/types/runtime/jsapi-modules/filesystem.d.ts +19 -0
  156. package/lib/types/runtime/jsapi-modules/index.d.ts +9 -0
  157. package/lib/types/runtime/jsapi-modules/interaction.d.ts +4 -0
  158. package/lib/types/runtime/jsapi-modules/location.d.ts +3 -0
  159. package/lib/types/runtime/jsapi-modules/media.d.ts +13 -0
  160. package/lib/types/runtime/jsapi-modules/network.d.ts +3 -0
  161. package/lib/types/runtime/jsapi-modules/storage.d.ts +26 -0
  162. package/lib/types/runtime/jsapi-modules/system.d.ts +4 -0
  163. package/lib/types/runtime/jsapi-modules/types.d.ts +21 -0
  164. package/lib/types/runtime/jsapi-modules/window-info.d.ts +43 -0
  165. package/lib/types/runtime/request/host-request.d.ts +13 -0
  166. package/lib/types/runtime/request/request-manager-frame.d.ts +29 -0
  167. package/lib/types/runtime/request/request-runtime.d.ts +26 -0
  168. package/lib/types/runtime/request/request-types.d.ts +26 -0
  169. package/lib/types/runtime/request/sse-text-framer.d.ts +16 -0
  170. package/lib/types/seal-config.d.ts +134 -0
  171. package/lib/types/sw/index.d.ts +9 -0
  172. package/lib/types/sw/parse-raw.d.ts +34 -0
  173. package/lib/types/sw/protocol.d.ts +19 -0
  174. package/lib/types/sw/served-entry.d.ts +9 -0
  175. package/lib/types/sw/service-worker-content-host.d.ts +11 -0
  176. package/lib/types/sw/service-worker-host.d.ts +74 -0
  177. package/lib/types/sw/service-worker-renderer.d.ts +10 -0
  178. package/lib/types/sw/worker/fs-codec.d.ts +23 -0
  179. package/lib/types/sw/worker/fs-ops.d.ts +22 -0
  180. package/lib/types/sw/worker/fs-store.d.ts +29 -0
  181. package/lib/types/sw/worker/globals.d.ts +50 -0
  182. package/lib/types/sw/worker/main.d.ts +6 -0
  183. package/lib/types/sw/worker/mime.d.ts +2 -0
  184. package/lib/types/sw/worker/mount-store.d.ts +48 -0
  185. package/lib/types/sw/worker/paths.d.ts +4 -0
  186. package/lib/types/sw/worker/serve.d.ts +13 -0
  187. package/lib/types/tracker/constants.d.ts +14 -0
  188. package/lib/types/tracker/default-tracker.d.ts +19 -0
  189. package/lib/types/tracker/index.d.ts +70 -0
  190. package/lib/types/transport/bridge-protocol.d.ts +78 -0
  191. package/lib/types/transport/iframe-transport.d.ts +39 -0
  192. package/lib/types/transport/index.d.ts +14 -0
  193. package/lib/types/transport/jsapi-bridge-messages.d.ts +36 -0
  194. package/lib/types/transport/types.d.ts +48 -0
  195. package/lib/types/transport/webview-transport.d.ts +52 -0
  196. package/lib/types/types/events.d.ts +130 -0
  197. package/lib/types/types/index.d.ts +11 -0
  198. package/lib/types/types/inspector.d.ts +172 -0
  199. package/lib/types/types/jsapi.d.ts +18 -0
  200. package/lib/types/types/options.d.ts +851 -0
  201. package/lib/types/types/renderer.d.ts +145 -0
  202. package/lib/types/utils/ancestor-scroll.d.ts +11 -0
  203. package/lib/types/utils/error-svg.d.ts +12 -0
  204. package/lib/types/utils/frameless-shell.d.ts +114 -0
  205. package/lib/types/utils/miniapp-chrome-svg.d.ts +47 -0
  206. package/lib/types/utils/package-constants.d.ts +8 -0
  207. package/lib/types/utils/screenshot.d.ts +14 -0
  208. package/lib/types/utils/simulator-pc-guard.d.ts +10 -0
  209. package/lib/types/utils/stage-fit.d.ts +6 -0
  210. package/lib/types/utils/touch-emulate.d.ts +26 -0
  211. package/lib/types/utils/zip-entry.d.ts +13 -0
  212. package/lib/types/workbench/index.d.ts +63 -0
  213. package/lib/types/workbench/preview-transition.d.ts +8 -0
  214. package/lib/types/workbench/server/artifact.d.ts +8 -0
  215. package/lib/types/workbench/server/index.d.ts +19 -0
  216. package/lib/types/workbench/server/watch.d.ts +6 -0
  217. package/lib/types/workbench/view.d.ts +36 -0
  218. package/lib/types/worker/adapters/csp-policy.d.ts +7 -0
  219. package/lib/types/worker/adapters/host-lifecycle.d.ts +5 -0
  220. package/lib/types/worker/adapters/mount-recovery.d.ts +2 -0
  221. package/lib/types/worker/adapters/package-policy.d.ts +12 -0
  222. package/lib/types/worker/adapters/page-lifecycle.d.ts +1 -0
  223. package/lib/types/worker/adapters/protocol.d.ts +49 -0
  224. package/lib/types/worker/adapters/scripts.d.ts +2 -0
  225. package/lib/types/worker/adapters/service-worker.d.ts +2 -0
  226. package/lib/workbench-server.mjs +183 -0
  227. package/lib/workbench.js +1404 -0
  228. package/package.json +61 -4
  229. package/scripts/mock-cli-dev.mjs +52 -0
@@ -0,0 +1,371 @@
1
+ # Miniapp Simulator 远程模式接入与使用指南
2
+
3
+ ## 1. 接入前准备
4
+
5
+ 宿主页面需要满足:
6
+
7
+ - 使用 HTTPS;本地 Simulator Server 调试可使用 `http://localhost` 或 `http://127.0.0.1`。
8
+ - CSP 的 `connect-src` 放行 Simulator origin,用于请求 `/simulator/runtime-manifest`。
9
+ - CSP 的 `frame-src` 放行 Simulator origin,用于加载远端 Runtime iframe。
10
+ - 网关不能给 Simulator 页面附加 `X-Frame-Options: SAMEORIGIN`。
11
+
12
+ 业务接入使用以下服务地址:
13
+
14
+ | 环境 | `serviceUrl` |
15
+ | --- | --- |
16
+ | 本地业务联调、SIT、Staging | `https://miniapp-sandbox.beta.xiaohongshu.com/simulator/` |
17
+ | Production | `https://miniapp-sandbox.xiaohongshu.com/simulator/` |
18
+ | Simulator Server 本地开发 | `http://127.0.0.1:5174/simulator/` |
19
+
20
+ 建议由业务项目封装环境映射,不要在每个页面重复判断。
21
+
22
+ ## 2. 最小接入
23
+
24
+ ```ts
25
+ import {
26
+ BusinessLine,
27
+ createRemoteMiniAppSimulator,
28
+ type RemoteMiniAppSimulator,
29
+ } from "@skillbuilder/miniapp-simulator/remote";
30
+
31
+ const simulator: RemoteMiniAppSimulator = createRemoteMiniAppSimulator({
32
+ mount: document.querySelector("#simulator")!,
33
+ serviceUrl:
34
+ process.env.NODE_ENV === "production"
35
+ ? "https://miniapp-sandbox.xiaohongshu.com/simulator/"
36
+ : "https://miniapp-sandbox.beta.xiaohongshu.com/simulator/",
37
+ appId: "current-miniapp-id",
38
+ businessLine: BusinessLine.creator,
39
+ tracker: true,
40
+ gateway: {
41
+ edith: "https://edith.xiaohongshu.com",
42
+ www: "https://www.xiaohongshu.com",
43
+ },
44
+ hostApi: {
45
+ getUserInfo: async () => ({
46
+ userId: "current-user-id",
47
+ nickname: "当前用户",
48
+ avatar: "https://example.com/avatar.png",
49
+ }),
50
+ },
51
+ options: {
52
+ contentMode: "fullscreen",
53
+ viewport: { width: 390, height: 844 },
54
+ phoneFrame: false,
55
+ touchEmulation: true,
56
+ stageFit: false,
57
+ },
58
+ });
59
+
60
+ simulator.on("error", error => {
61
+ console.error("[miniapp-simulator]", error);
62
+ });
63
+
64
+ await simulator.ready;
65
+ ```
66
+
67
+ 参数分层:
68
+
69
+ | 参数 | 位置 | 含义 |
70
+ | --- | --- | --- |
71
+ | `gateway` | 顶层 | 注入 `miniToolEnv.gateways` 的网关对象;包含 `edith`、`www`,后续可继续扩展其他网关 |
72
+ | `mount` | 顶层 | 宿主挂载节点 |
73
+ | `serviceUrl` | 顶层 | Simulator Server 入口 |
74
+ | `fallbackServiceUrls` | 顶层 | 主服务失败后的独立备用服务 |
75
+ | `appId` | 顶层 | 当前小应用 ID,同时参与远端策略匹配 |
76
+ | `businessLine` | 顶层、必填 | `BusinessLine` 枚举值,用于默认 Host API、策略、打点和 AI 服务路由 |
77
+ | `tracker` | 顶层 | 是否启用 Runtime 打点 |
78
+ | `hostApi` | 顶层 | 运行在宿主 Realm 的自定义 Bridge 实现 |
79
+ | `options` | 内层 | 可序列化的模拟器显示和交互配置 |
80
+
81
+ `BusinessLine` 提供 `skillDesignable`、`creator`、`mars`、`dev` 四个成员,值分别为
82
+ `skill-designable`、`creator`、`mars`、`dev`。
83
+
84
+ `renderer`、`serviceWorker`、`security`、`jsapi`、`runtimeLimits` 不由宿主传入。它们由远端
85
+ Runtime、Service Worker 和 Apollo 统一管理。
86
+
87
+ Runtime 会在连接时按 `appId`、用户 ID 和 `businessLine` 请求一次统一配置,取得 CSP、性能保护和
88
+ JSAPI 配置。`businessLine` 缺失或为空时薄 SDK 会拒绝创建实例。
89
+
90
+ 远端配置的作用规则:
91
+
92
+ - `unsupported` 只调整明确不支持或没有 handler 的 JSAPI 提示,不影响已有实现。
93
+ - API 名称可精确覆盖对应实现,例如 `postNote`;支持 `{ toast: "文案" }` 或
94
+ `{ alert: "文案" }`,两者同时存在时 Alert 优先。
95
+ - 精确配置只展示提示并成功返回 `{}`,不会生成 API 专属返回字段。
96
+ - 优先级为:宿主 `hostApi` → 单 API 远端配置 → `unsupported` → Runtime 默认行为。
97
+ - 配置在实例连接 Runtime 时读取;配置更新后需要新建模拟器实例才能取得新值。
98
+
99
+ ## 3. 加载小应用
100
+
101
+ ### 加载 ZIP
102
+
103
+ ```ts
104
+ const response = await fetch(zipUrl);
105
+ const zipBlob = await response.blob();
106
+
107
+ const result = await simulator.loadZip(zipBlob);
108
+ console.log(result.entry, result.files);
109
+ ```
110
+
111
+ 远程模式的 Runtime 已内置 JSZip,宿主不需要传入 `jszip`。ZIP 不上传 Node 服务,直接从宿主浏览器
112
+ 传给 Runtime 并在浏览器内解压。
113
+
114
+ ### 加载文件表
115
+
116
+ ```ts
117
+ await simulator.loadFiles({
118
+ "index.html": "<!doctype html><div id=\"app\"></div><script src=\"./app.js\"></script>",
119
+ "app.js": "document.querySelector('#app').textContent = 'Hello';",
120
+ });
121
+ ```
122
+
123
+ ### 加载远程页面
124
+
125
+ ```ts
126
+ await simulator.loadApp("https://example.com/miniapp/index.html", {
127
+ query: { source: "creator-preview" },
128
+ });
129
+ ```
130
+
131
+ ### 只加载模拟器壳层
132
+
133
+ ```ts
134
+ await simulator.load();
135
+ ```
136
+
137
+ 适用于半屏模式的空态、Permission Sheet 或 Note Preview 调试。
138
+
139
+ ## 4. 宿主 Host API
140
+
141
+ 函数不能序列化到跨域 iframe。薄 SDK 会在宿主保留函数,通过 MessageChannel 接收 Runtime 请求并执行:
142
+
143
+ ```ts
144
+ const simulator = createRemoteMiniAppSimulator({
145
+ mount,
146
+ serviceUrl,
147
+ appId,
148
+ businessLine: BusinessLine.creator,
149
+ hostApi: {
150
+ getUserInfo: async () => ({
151
+ userId: currentUser.id,
152
+ nickname: currentUser.nickname,
153
+ avatar: currentUser.avatar,
154
+ }),
155
+ postNote: async request => {
156
+ return publishFromCreator(request.message);
157
+ },
158
+ openRedPage: async request => {
159
+ return openCreatorPage(request.message);
160
+ },
161
+ },
162
+ });
163
+ ```
164
+
165
+ 规则:
166
+
167
+ - `getUserInfo` 是 userId 的统一来源;不要单独传 tracker userId。
168
+ - Runtime 会先注册 `businessLine` 对应的默认行为,再用宿主 `hostApi` 覆盖同名实现。
169
+ - 宿主可以在运行期调用 `simulator.hostApi.set()`、`registerAll()`、`remove()` 或 `clear()`。
170
+ - `appId`、`userId`、`businessLine` 会用于 Apollo CSP 和性能策略匹配;这些字段属于模拟器配置上下文,
171
+ 不应作为服务端安全鉴权凭据。
172
+
173
+ Runtime 内置 `setStorage`、`getStorage`、`getStorageInfo`、`removeStorage`、`clearStorage` 默认实现。
174
+ 数据持久化在 Simulator origin 的 IndexedDB,按 `businessLine + appId` 隔离;单 key 上限 1MB,
175
+ 每个小工具总上限 10MB。实现随远端 Runtime release 发布,宿主无需升级薄 SDK;如宿主注册同名
176
+ `hostApi`,仍按上述优先级覆盖默认实现。
177
+
178
+ ## 5. 常用实例能力
179
+
180
+ ```ts
181
+ simulator.setViewport({ width: 430, height: 932 });
182
+
183
+ await simulator.switchContentMode("half");
184
+ await simulator.switchPhoneFrame(false);
185
+ await simulator.reload();
186
+
187
+ simulator.notePreview.update({ title: "新的笔记标题" });
188
+ simulator.notePreview.updateUser({ nickname: "新的用户昵称" });
189
+ simulator.notePreview.updateAppCard({ name: "小工具名称" });
190
+
191
+ await simulator.permissionSheet.show(["camera", "microphone"]);
192
+ simulator.permissionSheet.hide();
193
+
194
+ simulator.inspector.enable();
195
+ simulator.inspector.setSelectionMode("multiple");
196
+ const sceneTree = await simulator.inspector.getSceneTree();
197
+
198
+ const image = await simulator.capture({ fullPage: false });
199
+ ```
200
+
201
+ 使用 `ready.capabilities` 判断远端 Runtime 是否支持可选能力:
202
+
203
+ ```ts
204
+ const ready = await simulator.ready;
205
+ if (ready.capabilities.includes("capture")) {
206
+ const image = await simulator.capture();
207
+ }
208
+ ```
209
+
210
+ ## 6. 事件订阅
211
+
212
+ ```ts
213
+ const unsubscribeError = simulator.on("error", error => {
214
+ console.error(error.code, error.message);
215
+ });
216
+
217
+ const unsubscribeRender = simulator.on("renderDone", event => {
218
+ console.log("rendered", event.duration);
219
+ });
220
+
221
+ const unsubscribeSelection = simulator.on("elementSelected", selection => {
222
+ console.log(selection);
223
+ });
224
+
225
+ const unsubscribeConsole = simulator.on("console", event => {
226
+ console[event.level](event.message);
227
+ });
228
+
229
+ // 页面不再需要订阅时主动解除。
230
+ unsubscribeError();
231
+ unsubscribeRender();
232
+ unsubscribeSelection();
233
+ unsubscribeConsole();
234
+ ```
235
+
236
+ 常用事件包括:`load`、`renderDone`、`error`、`navigation`、`console`、`guestError`、
237
+ `performance`、`elementSelected`、`inspectorChange`。
238
+
239
+ ## 7. React 接入
240
+
241
+ ```tsx
242
+ function MiniappPreview({ appId, zip }: { appId: string; zip?: Blob }) {
243
+ const mountRef = useRef<HTMLDivElement>(null);
244
+
245
+ useEffect(() => {
246
+ if (!mountRef.current) return;
247
+ let disposed = false;
248
+
249
+ const simulator = createRemoteMiniAppSimulator({
250
+ mount: mountRef.current,
251
+ serviceUrl: SIMULATOR_SERVICE_URL,
252
+ appId,
253
+ businessLine: BusinessLine.creator,
254
+ tracker: true,
255
+ hostApi: {
256
+ getUserInfo: async () => getCurrentUser(),
257
+ },
258
+ options: {
259
+ contentMode: "fullscreen",
260
+ viewport: { width: 390, height: 844 },
261
+ phoneFrame: false,
262
+ },
263
+ });
264
+
265
+ void simulator.ready
266
+ .then(() => (zip ? simulator.loadZip(zip) : simulator.load()))
267
+ .catch(error => {
268
+ if (!disposed) console.error(error);
269
+ });
270
+
271
+ return () => {
272
+ disposed = true;
273
+ simulator.destroy("unmount");
274
+ };
275
+ }, [appId, zip]);
276
+
277
+ return <div ref={mountRef} style={{ width: "100%", height: "100%" }} />;
278
+ }
279
+ ```
280
+
281
+ 注意:
282
+
283
+ - React 开发模式可能执行挂载、卸载、重新挂载,用 `disposed` 忽略已经销毁实例的异步结果。
284
+ - 清理函数必须调用 `destroy()`,否则 iframe、MessagePort 和 SW ZIP 文件可能继续占用资源。
285
+ - 频繁变化的 viewport 不要重建实例,使用 `setViewport()`。
286
+ - `appId` 改变时应创建新实例,避免策略、打点和 FS scope 混用。
287
+
288
+ ## 8. 同页多个模拟器
289
+
290
+ ```ts
291
+ const simulators = apps.map((app, index) =>
292
+ createRemoteMiniAppSimulator({
293
+ mount: mounts[index],
294
+ serviceUrl,
295
+ appId: app.id,
296
+ businessLine: BusinessLine.creator,
297
+ options: { viewport: { width: 390, height: 844 } },
298
+ }),
299
+ );
300
+
301
+ await Promise.all(simulators.map((simulator, index) => simulator.loadZip(apps[index].zip)));
302
+
303
+ // 页面退出时逐个销毁。
304
+ for (const simulator of simulators) simulator.destroy("page-unmount");
305
+ ```
306
+
307
+ 每个实例拥有独立外层 iframe、sessionId、MessageChannel 和 mountId。同 release 最多同时挂载 16 个
308
+ 小应用。Web 模式的数据隔离不等于进程隔离;需要逐实例硬内存配额时使用 Electron。
309
+
310
+ ## 9. 服务降级
311
+
312
+ ```ts
313
+ const simulator = createRemoteMiniAppSimulator({
314
+ mount,
315
+ serviceUrl: PRIMARY_SIMULATOR_SERVICE_URL,
316
+ fallbackServiceUrls: [BACKUP_SIMULATOR_SERVICE_URL],
317
+ appId,
318
+ businessLine: BusinessLine.creator,
319
+ });
320
+ ```
321
+
322
+ 备用地址必须是实际独立部署、能够提供相同协议 release 的 Simulator Server。只配置另一个指向同一
323
+ 故障集群的域名不能提供有效降级。
324
+
325
+ Client 会先依次请求主、备用服务。网络错误和最终非 2xx 响应会在等待 100ms 后重试一轮,请求超时由
326
+ 网关控制;2xx 响应中的协议不匹配、响应结构非法和 document origin 不匹配不会重试同一地址。
327
+ 即使没有配置 `fallbackServiceUrls`,主地址的瞬时故障也有一次重试机会。
328
+
329
+ ## 10. 常见问题
330
+
331
+ ### `/runtime-manifest` 请求失败
332
+
333
+ 检查宿主 `connect-src`、Simulator Server 网关和
334
+ `/simulator/runtime-manifest?protocolVersion=6` 的 CORS。
335
+
336
+ ### iframe 被宿主 CSP 阻止
337
+
338
+ 把 Simulator origin 加入宿主 `frame-src`,并确认网关没有设置 `X-Frame-Options: SAMEORIGIN`。
339
+
340
+ ### Service Worker 注册失败
341
+
342
+ 检查 Runtime 是否为安全上下文、`/releases/:buildId/sw.js` 是否返回 JavaScript MIME、
343
+ `Service-Worker-Allowed` 是否覆盖当前 release 的 `/app/` scope,以及 CDN SW module 是否允许 CORS。
344
+
345
+ ### 返回 HTTP 426
346
+
347
+ Apollo release `list` 中没有与薄 SDK protocolVersion 一致的版本。保留旧协议 release,或者升级业务方
348
+ 薄 SDK。
349
+
350
+ ### 模拟器显示正常但控制台出现 destroyed rejection
351
+
352
+ 所有异步 `ready`、`loadZip`、`loadApp`、`reload` 调用都应处理 rejection;组件卸载时设置 disposed,
353
+ 再调用 `destroy()`。
354
+
355
+ ### 模拟器卡死或内存过高
356
+
357
+ Web 模式使用 JS Heap 水位和 iframe 心跳兜底。恢复提示由薄 SDK展示,用户确认后重建 Runtime 并重放
358
+ 最近一次 load。完整 Renderer 内存和逐实例进程管控需要 Electron。
359
+
360
+ ## 11. 接入检查表
361
+
362
+ - [ ] 按环境配置正确的 `serviceUrl`。
363
+ - [ ] 宿主 CSP 放行 Simulator 的 `connect-src` 和 `frame-src`。
364
+ - [ ] `appId`、`businessLine` 位于顶层。
365
+ - [ ] `getUserInfo` 通过 `hostApi` 提供。
366
+ - [ ] ZIP 使用 `loadZip()`,无需宿主传 JSZip。
367
+ - [ ] 等待 `ready` 并处理 Promise rejection。
368
+ - [ ] 组件卸载时调用 `destroy()`。
369
+ - [ ] 多实例分别保存引用并使用不同 appId。
370
+ - [ ] 可选新能力通过 `ready.capabilities` 判断。
371
+ - [ ] 生产环境验证 Runtime 和 SW CDN CORS。
@@ -0,0 +1,247 @@
1
+ # 模拟器 Request 请求方案
2
+
3
+ ## 1. 结论
4
+
5
+ 模拟器保留两条独立请求链路:
6
+
7
+ - `xhs.miniTool.request` 是面向小工具开发者的公开 API,在无宿主身份的隔离 iframe 中执行。
8
+ - `xhsRequest` 是 JS SDK 内部 Bridge 能力,通过宿主注入的 `hostApi.request` 执行,用于 `xhs.AI` 等平台托管能力。
9
+
10
+ 两者复用请求参数、`RequestTask`、事件和错误模型,但不共享网络权限。公开链路不能被 `hostApi.request` 覆盖,避免开发者请求获得宿主 Cookie、签名或内部网关能力。
11
+
12
+ ## 2. 能力边界
13
+
14
+ | 维度 | `xhs.miniTool.request` | `xhsRequest` |
15
+ | --- | --- | --- |
16
+ | 定位 | 公开 JSAPI | SDK 内部 Bridge 能力 |
17
+ | 调用方 | 小工具业务代码 | `xhs.AI` 等 SDK 内部模块 |
18
+ | 执行位置 | 独立 request manager iframe 内的 `fetch` | 宿主注入的 `hostApi.request` |
19
+ | 身份与 Cookie | `credentials: omit`,不携带宿主 Cookie | 由宿主决定,可进入登录态、验签和拦截链 |
20
+ | 跨域 | 遵循浏览器 CORS;iframe 为 opaque origin | 遵循宿主 HTTP 实现及运行环境约束 |
21
+ | 流式响应 | 读取 Fetch `ReadableStream` | 宿主返回 `ReadableStream` 或完整字符串 |
22
+ | API 暴露 | 正式公共 API | 不进入公共类型和正式 API 面;开发构建可临时暴露用于链路验证 |
23
+
24
+ ## 3. 总体架构
25
+
26
+ ```mermaid
27
+ flowchart LR
28
+ A[小工具业务] -->|xhs.miniTool.request| B[JS SDK RequestTask]
29
+ C[xhs.AI / SDK 内部模块] -->|xhsRequest| B
30
+ B -->|request / xhsRequest + taskId| D[Bridge]
31
+ D -->|request| E[RequestRuntime.executePublic]
32
+ E -->|postMessage| F[隔离 Request Manager iframe]
33
+ F -->|fetch / credentials omit| G[开发者服务]
34
+ D -->|xhsRequest| H[RequestRuntime.executeInternal]
35
+ H -->|统一 Host Request 契约| I[hostApi.request]
36
+ I -->|Cookie / 验签 / 拦截 / Trace| J[平台服务]
37
+ F -.->|headers / SSE chunk| D
38
+ H -.->|headers / SSE chunk| D
39
+ D -.->|taskId 路由| B
40
+ ```
41
+
42
+ `RequestRuntime` 是统一调度层,负责参数校验、活跃任务管理、取消和事件回传;真正的 I/O 由隔离 iframe 或宿主适配器完成。
43
+
44
+ ## 4. 为什么公开 request 走隔离 iframe
45
+
46
+ 公开请求不能直接在小工具渲染 iframe 或宿主页面执行:
47
+
48
+ - 小工具渲染 iframe 承载不可信业务代码,并受页面 CSP、运行时封印和应用生命周期影响,不适合作为独立网络执行面。
49
+ - 宿主页面拥有 Cookie、登录态、HTTP 拦截器和签名能力,直接复用会扩大公开 API 的权限。
50
+ - 独立 iframe 可以使用 `sandbox="allow-scripts"` 形成 opaque origin,配合 `credentials: omit`、`no-referrer`、受控 CSP 和请求头过滤,建立清晰的无身份网络边界。
51
+ - request manager 与单个模拟器实例绑定,可以独立维护任务表;模拟器销毁时直接取消请求并移除 iframe。
52
+
53
+ ### 4.1 为什么不走 Service Worker
54
+
55
+ 模拟器中的 Service Worker 负责 ZIP 文件表、虚拟 URL 和静态资源加载;公开 request 是显式 JSAPI RPC,两类问题的边界不同。
56
+
57
+ | 考量 | 隔离 iframe | Service Worker |
58
+ | --- | --- | --- |
59
+ | 适用问题 | 执行显式请求 RPC | 拦截受 scope 控制的页面和子资源请求 |
60
+ | 安全边界 | `sandbox` 去同源形成 opaque origin | 运行在注册 origin,不能提供同等直接的 opaque-origin 实例边界 |
61
+ | 生命周期 | DOM 实例所有;创建、取消、销毁可预测 | 浏览器管理,可能休眠/重启,不能与模拟器实例严格同生共死 |
62
+ | 隔离粒度 | 每个模拟器实例一个 manager 和任务表 | 同一 registration/scope 可被多个页面或实例共享 |
63
+ | 部署条件 | 可使用内联 data URL 或服务端提供的 frame URL | 要求安全上下文、同源脚本、合法 scope 和注册成功 |
64
+ | 版本管理 | 随 Runtime 版本加载并随实例销毁 | 存在安装、激活、更新和旧 worker 接管窗口 |
65
+ | 宿主影响 | 不接管宿主或小工具的正常资源请求 | 扩大 fetch 拦截面,可能与现有模拟器 SW 或宿主 SW 冲突 |
66
+ | 流式回传 | iframe 内直接读流,通过 `postMessage + taskId` 回传 | 需要额外的 client 定位、消息关联和 worker 存活处理 |
67
+
68
+ 采用 Service Worker 还会带来以下具体问题:
69
+
70
+ 1. SW 只能控制其注册 origin 和 scope 下的 client,不能从任意 CDN 跨域注册,也不能在 opaque origin/data URL 中注册。
71
+ 2. 当前远程模拟器已经使用版本化 SW 承载虚拟文件系统。把业务 request 混入该 SW 会把“包内资源解析”和“对外网络权限”耦合到同一个全局拦截器。
72
+ 3. 多模拟器、多标签页可能共享 SW registration,任务隔离、升级切换和故障回收都比实例级 iframe 更复杂。
73
+ 4. `xhs.miniTool.request` 已经通过 Bridge 明确发起,不需要 SW 的透明 fetch 拦截能力。
74
+ 5. 隔离 iframe 能直接执行 Fetch 和 ReadableStream,并用现有 `taskId` 协议回传响应头、SSE 分片和终态,链路更短。
75
+
76
+ 因此,Service Worker 继续负责“把 ZIP 文件映射为同源虚拟文件系统”;隔离 iframe 负责“公开、无身份、显式 request”;宿主 `hostApi.request` 负责“内部、有身份、平台托管 request”。
77
+
78
+ ## 5. SDK 请求契约
79
+
80
+ | 字段 | 类型 | 默认值 | 说明 |
81
+ | --- | --- | --- | --- |
82
+ | `url` | string | 必填 | 非空 URL;公开链路仅允许 `http:` 和 `https:` |
83
+ | `method` | GET/POST/PUT/DELETE/HEAD/OPTIONS | GET | 运行层统一转为大写 |
84
+ | `header` | `Record<string, string>` | 空 | 公开链路移除受保护头;内部链路交给宿主 |
85
+ | `data` | unknown | 空 | 不支持 `ArrayBuffer` 和 TypedArray |
86
+ | `dataType` | json/text | json | json 模式尽力解析字符串响应 |
87
+ | `responseType` | text | text | 当前仅支持文本响应 |
88
+ | `timeout` | number | 60000 ms | 必须大于 0;超时中止底层请求 |
89
+ | `enableChunked` | boolean | false | 开启 SSE 分片消费 |
90
+ | `success/fail/complete` | callback | 空 | `complete` 在成功或失败后执行 |
91
+
92
+ 请求同步返回 `RequestTask`:
93
+
94
+ ```ts
95
+ interface RequestTask {
96
+ abort(): void
97
+ onHeadersReceived(callback: (result: {
98
+ statusCode: number
99
+ header: Record<string, string>
100
+ }) => void): void
101
+ offHeadersReceived(callback?: Function): void
102
+ onChunkReceived(callback: (result: { data: string }) => void): void
103
+ offChunkReceived(callback?: Function): void
104
+ }
105
+ ```
106
+
107
+ SDK 先返回 Task,再异步发起 Bridge 调用,使调用方可以提前注册响应头和分片监听。任务完成、失败或取消后会清理订阅并忽略迟到事件。
108
+
109
+ ## 6. Bridge 协议
110
+
111
+ - 请求事件:`request` 或 `xhsRequest`,消息体包含统一参数和唯一 `taskId`。
112
+ - 响应头事件:`onHeadersReceivedRequest`,按 `taskId` 投递。
113
+ - 流分片事件:`onEventStream`,按 `taskId` 投递。
114
+ - 取消事件:`abortRequest`,只携带 `taskId`。
115
+ - 终态:success 返回 `statusCode`、`header`、`data`;fail 返回 `errCode` 和 `errMsg`。
116
+
117
+ ## 7. 公开 request 执行链路
118
+
119
+ 1. SDK 创建 `RequestTask` 和 `taskId`,异步发送 `request`。
120
+ 2. `RequestRuntime.executePublic` 校验参数。
121
+ 3. 运行层按需创建隐藏 request manager iframe,通过 `postMessage` 发送请求。
122
+ 4. iframe 使用 `fetch` 请求,将响应头、SSE 分片和终态结果回传模拟器。
123
+ 5. 模拟器通过 Bridge 投递给对应 `RequestTask`。
124
+
125
+ 隔离策略:
126
+
127
+ - iframe sandbox 仅启用 `allow-scripts`,不启用 `allow-same-origin`。
128
+ - `referrerPolicy` 为 `no-referrer`;Fetch 固定 `credentials: omit`。
129
+ - CSP 只开放脚本自身执行及 `http/https/ws/wss` 连接;URL 进一步限制为 `http:` 或 `https:`。
130
+ - 过滤 `cookie`、`referer`、`origin`、`user-agent`、`host`、`content-length`。
131
+ - 响应头统一小写并移除 `set-cookie`。
132
+
133
+ 公开 request 的目标服务必须允许浏览器跨域请求。由于执行上下文是 opaque origin,服务端需要按实际预检请求配置 CORS。
134
+
135
+ ## 8. 内部 xhsRequest 执行链路
136
+
137
+ 1. `xhs.AI` 等 SDK 内部模块发送 `xhsRequest`。
138
+ 2. `RequestRuntime.executeInternal` 读取 `hostApi.request`;未注入时返回 API unavailable。
139
+ 3. 运行层创建 `AbortController` 和超时计时器,转换为通用宿主请求契约。
140
+ 4. 宿主适配 Launcher HTTP、XHR、Fetch 或其他 HTTP 库,处理身份、Cookie、验签、拦截器和链路信息。
141
+ 5. 运行层校验并归一化宿主响应,回传响应头、SSE 分片和终态。
142
+
143
+ ```ts
144
+ type MiniAppHostRequest = (options: {
145
+ url: string
146
+ method: string
147
+ header?: Record<string, string>
148
+ data?: unknown
149
+ responseType: 'text'
150
+ enableChunked: boolean
151
+ signal: AbortSignal
152
+ }) => Promise<{
153
+ statusCode: number
154
+ header?: Record<string, string>
155
+ data?: unknown | ReadableStream<Uint8Array | string>
156
+ }>
157
+ ```
158
+
159
+ 宿主必须响应 `signal`。HTTP 非 2xx 状态仍按正常响应返回;传输失败、取消、超时或适配器异常进入 fail。宿主只处理通用 HTTP 参数,不感知 `taskId` 和 Bridge 事件。
160
+
161
+ ## 9. 参数序列化与响应归一化
162
+
163
+ | 场景 | 处理规则 |
164
+ | --- | --- |
165
+ | GET/HEAD | `data` 序列化到 query |
166
+ | 无 Content-Type 的非 GET | 自动使用 `application/json` |
167
+ | `application/json` | 非字符串请求体执行 `JSON.stringify` |
168
+ | `application/x-www-form-urlencoded` | 按 query 规则序列化 |
169
+ | 其他 Content-Type | 字符串原样发送,其他值转字符串 |
170
+ | 普通响应 | 头转小写、移除 `set-cookie`;json 模式尽力解析 |
171
+ | SSE | 按空行边界组装原始事件帧;每帧触发 `onChunkReceived`,终态 data 为空字符串 |
172
+
173
+ ## 10. 超时、取消与并发
174
+
175
+ - 两条链路都创建超时计时器,到期后中止底层请求并返回 `REQUEST_TIMEOUT`。
176
+ - `RequestTask.abort()` 立即将 SDK 任务置为终态、清理订阅,并发送 `abortRequest(taskId)`。
177
+ - 模拟器销毁时执行 `abortAll`,取消全部活跃请求并移除 request manager iframe。
178
+ - 活跃任务以 `taskId` 存储;重复 `taskId` 为非法参数,响应头和分片只投递给匹配任务。
179
+ - 终态清除计时器、活跃任务记录和 SDK 事件订阅。
180
+
181
+ ## 11. 错误模型
182
+
183
+ | 错误码 | 名称 | 触发条件 |
184
+ | --- | --- | --- |
185
+ | 10001 | INVALID_PARAM | URL/taskId、方法或 timeout 非法,二进制 data,非 text responseType,重复 taskId |
186
+ | 10002 | API_UNAVAILABLE | `xhsRequest` 未找到 `hostApi.request` |
187
+ | 10003 | URL_SCHEME_NOT_ALLOWED | 公开 request 使用非 http/https 协议 |
188
+ | 10101 | REQUEST_TIMEOUT | 超过 timeout |
189
+ | 10102 | REQUEST_ABORTED | 调用方取消或模拟器销毁 |
190
+ | 15201 | REQUEST_FAILED | Fetch 失败、宿主异常、响应结构非法或二进制响应 |
191
+
192
+ ## 12. 接入要求
193
+
194
+ 小工具开发者:
195
+
196
+ - 普通业务请求使用 `xhs.miniTool.request`。
197
+ - 不直接依赖 `xhsRequest`;平台托管能力通过 `xhs.AI` 等公开模块使用。
198
+ - SSE 设置 `enableChunked: true` 和 `dataType: 'text'`,通过 Task 注册 `onChunkReceived`。
199
+
200
+ 模拟器宿主:
201
+
202
+ ```ts
203
+ createRemoteMiniAppSimulator({
204
+ // ...其他配置
205
+ hostApi: {
206
+ request: async (options) => {
207
+ // 适配 Launcher HTTP / Fetch / XHR,透传 options.signal
208
+ return { statusCode, header, data }
209
+ },
210
+ },
211
+ })
212
+ ```
213
+
214
+ - 仅在需要 SDK 内部平台请求时注入 `hostApi.request`。
215
+ - 宿主决定凭证策略、签名、拦截器、Trace Header 和业务网关。
216
+ - 不得把 Cookie、Token 或签名能力反向暴露给公开 request。
217
+
218
+ ## 13. 当前限制
219
+
220
+ - 不支持二进制请求体和响应体。
221
+ - `responseType` 只支持 `text`。
222
+ - 公开 request 受 CORS 约束,不能携带宿主 Cookie或设置受保护请求头。
223
+ - 流式分片只识别 `Content-Type: text/event-stream`,输出未解析的 SSE 原始事件帧。
224
+ - 对象 query 是扁平键值序列化;复杂嵌套、数组和特殊编码由调用方预处理。
225
+ - Multipart 不接收二进制 `FormData` 作为跨 Bridge 数据;调用方构造字符串请求体,或由内部宿主链路适配。
226
+
227
+ ## 14. 验收清单
228
+
229
+ - [x] 公开 request:GET query、POST JSON、URL Encoded 可返回。
230
+ - [x] 内部 xhsRequest:经 `hostApi.request` 进入宿主 HTTP 拦截链。
231
+ - [x] 公开 request 不携带宿主 Cookie,受保护请求头被过滤。
232
+ - [x] SSE:响应头先到达,分片按完整事件帧顺序回调,终态正确。
233
+ - [x] abort、timeout、destroy 均中止任务并清理资源。
234
+ - [x] HTTP 非 2xx 保留 statusCode,传输错误进入 fail。
235
+ - [x] 缺少适配器、非法协议、非法参数和二进制数据返回明确错误码。
236
+ - [x] 并发请求按 taskId 隔离。
237
+
238
+ ## 15. 代码落点
239
+
240
+ | 模块 | 职责 |
241
+ | --- | --- |
242
+ | `miniapp-js-api/src/apis/request`(jsapi SDK 源码,已随包外移) | 请求参数、RequestTask、Bridge 发送和本地参数拒绝 |
243
+ | `miniapp-js-api/src/ai/request.ts`(已外移) | 内部 xhsRequest 到 AI SDK 普通/流式请求适配 |
244
+ | `miniapp-simulator/src/runtime/request-runtime.ts` | 双链路调度、校验、任务、超时和取消 |
245
+ | `miniapp-simulator/src/runtime/request-manager-frame.ts` | 公开请求的隔离 iframe、Fetch、安全策略和 SSE |
246
+ | `miniapp-simulator/src/runtime/host-request.ts` | 宿主请求适配、序列化、响应归一化和 SSE 分帧 |
247
+ | `miniapp-simulator/src/core/simulator.ts` | 注册 request、xhsRequest、abortRequest handler |