request-iframe 0.1.1 → 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 (208) hide show
  1. package/QUICKSTART.CN.md +4 -2
  2. package/QUICKSTART.md +4 -2
  3. package/README.CN.md +129 -33
  4. package/README.md +116 -15
  5. package/cdn/request-iframe-react.umd.js +3354 -0
  6. package/cdn/request-iframe-react.umd.js.map +1 -0
  7. package/cdn/request-iframe-react.umd.min.js +2 -0
  8. package/cdn/request-iframe-react.umd.min.js.map +1 -0
  9. package/cdn/request-iframe.umd.js +19735 -0
  10. package/cdn/request-iframe.umd.js.map +1 -0
  11. package/cdn/request-iframe.umd.min.js +4 -0
  12. package/cdn/request-iframe.umd.min.js.map +1 -0
  13. package/esm/api/client.js +29 -21
  14. package/esm/api/endpoint.js +229 -0
  15. package/esm/api/server.js +16 -8
  16. package/esm/constants/debug.js +17 -0
  17. package/esm/constants/index.js +84 -67
  18. package/esm/constants/log.js +11 -0
  19. package/esm/constants/messages.js +3 -0
  20. package/esm/constants/warn-once.js +15 -0
  21. package/esm/endpoint/facade.js +390 -0
  22. package/esm/endpoint/heartbeat/heartbeat.js +60 -0
  23. package/esm/endpoint/heartbeat/ping.js +20 -0
  24. package/esm/endpoint/index.js +13 -0
  25. package/esm/endpoint/infra/hub.js +316 -0
  26. package/esm/endpoint/infra/inbox.js +232 -0
  27. package/esm/endpoint/infra/outbox.js +408 -0
  28. package/esm/endpoint/stream/dispatcher.js +58 -0
  29. package/esm/endpoint/stream/errors.js +27 -0
  30. package/esm/endpoint/stream/factory.js +76 -0
  31. package/esm/endpoint/stream/file-auto-resolve.js +34 -0
  32. package/esm/endpoint/stream/file-writable.js +105 -0
  33. package/esm/endpoint/stream/handler.js +26 -0
  34. package/esm/{core → impl}/client.js +240 -317
  35. package/esm/{core → impl}/response.js +113 -155
  36. package/esm/impl/server.js +568 -0
  37. package/esm/index.js +13 -6
  38. package/esm/message/ack.js +27 -0
  39. package/esm/message/channel-cache.js +108 -0
  40. package/esm/message/channel.js +90 -4
  41. package/esm/message/dispatcher.js +88 -75
  42. package/esm/stream/error.js +22 -0
  43. package/esm/stream/index.js +3 -1
  44. package/esm/stream/readable-stream.js +45 -9
  45. package/esm/stream/stream-core.js +7 -2
  46. package/esm/stream/writable-stream.js +97 -26
  47. package/esm/utils/blob.js +16 -0
  48. package/esm/utils/cache.js +25 -76
  49. package/esm/utils/content-type.js +81 -0
  50. package/esm/utils/debug.js +156 -179
  51. package/esm/utils/hooks.js +130 -0
  52. package/esm/utils/id.js +14 -0
  53. package/esm/utils/iframe.js +20 -0
  54. package/esm/utils/index.js +11 -163
  55. package/esm/utils/is.js +3 -0
  56. package/esm/utils/logger.js +55 -0
  57. package/esm/utils/promise.js +3 -0
  58. package/esm/utils/window.js +31 -0
  59. package/library/api/client.d.ts.map +1 -1
  60. package/library/api/client.js +30 -22
  61. package/library/api/endpoint.d.ts +23 -0
  62. package/library/api/endpoint.d.ts.map +1 -0
  63. package/library/api/endpoint.js +235 -0
  64. package/library/api/server.d.ts +4 -1
  65. package/library/api/server.d.ts.map +1 -1
  66. package/library/api/server.js +16 -8
  67. package/library/constants/debug.d.ts +18 -0
  68. package/library/constants/debug.d.ts.map +1 -0
  69. package/library/constants/debug.js +23 -0
  70. package/library/constants/index.d.ts +22 -2
  71. package/library/constants/index.d.ts.map +1 -1
  72. package/library/constants/index.js +110 -67
  73. package/library/constants/log.d.ts +12 -0
  74. package/library/constants/log.d.ts.map +1 -0
  75. package/library/constants/log.js +17 -0
  76. package/library/constants/messages.d.ts +3 -0
  77. package/library/constants/messages.d.ts.map +1 -1
  78. package/library/constants/messages.js +3 -0
  79. package/library/constants/warn-once.d.ts +12 -0
  80. package/library/constants/warn-once.d.ts.map +1 -0
  81. package/library/constants/warn-once.js +22 -0
  82. package/library/endpoint/facade.d.ts +238 -0
  83. package/library/endpoint/facade.d.ts.map +1 -0
  84. package/library/endpoint/facade.js +398 -0
  85. package/library/endpoint/heartbeat/heartbeat.d.ts +34 -0
  86. package/library/endpoint/heartbeat/heartbeat.d.ts.map +1 -0
  87. package/library/endpoint/heartbeat/heartbeat.js +67 -0
  88. package/library/endpoint/heartbeat/ping.d.ts +18 -0
  89. package/library/endpoint/heartbeat/ping.d.ts.map +1 -0
  90. package/library/endpoint/heartbeat/ping.js +26 -0
  91. package/library/endpoint/index.d.ts +16 -0
  92. package/library/endpoint/index.d.ts.map +1 -0
  93. package/library/endpoint/index.js +114 -0
  94. package/library/endpoint/infra/hub.d.ts +170 -0
  95. package/library/endpoint/infra/hub.d.ts.map +1 -0
  96. package/library/endpoint/infra/hub.js +323 -0
  97. package/library/endpoint/infra/inbox.d.ts +73 -0
  98. package/library/endpoint/infra/inbox.d.ts.map +1 -0
  99. package/library/endpoint/infra/inbox.js +239 -0
  100. package/library/endpoint/infra/outbox.d.ts +149 -0
  101. package/library/endpoint/infra/outbox.d.ts.map +1 -0
  102. package/library/endpoint/infra/outbox.js +415 -0
  103. package/library/endpoint/stream/dispatcher.d.ts +33 -0
  104. package/library/endpoint/stream/dispatcher.d.ts.map +1 -0
  105. package/library/endpoint/stream/dispatcher.js +66 -0
  106. package/library/endpoint/stream/errors.d.ts +20 -0
  107. package/library/endpoint/stream/errors.d.ts.map +1 -0
  108. package/library/endpoint/stream/errors.js +32 -0
  109. package/library/endpoint/stream/factory.d.ts +44 -0
  110. package/library/endpoint/stream/factory.d.ts.map +1 -0
  111. package/library/endpoint/stream/factory.js +82 -0
  112. package/library/endpoint/stream/file-auto-resolve.d.ts +26 -0
  113. package/library/endpoint/stream/file-auto-resolve.d.ts.map +1 -0
  114. package/library/endpoint/stream/file-auto-resolve.js +41 -0
  115. package/library/endpoint/stream/file-writable.d.ts +33 -0
  116. package/library/endpoint/stream/file-writable.d.ts.map +1 -0
  117. package/library/endpoint/stream/file-writable.js +115 -0
  118. package/library/endpoint/stream/handler.d.ts +20 -0
  119. package/library/endpoint/stream/handler.d.ts.map +1 -0
  120. package/library/endpoint/stream/handler.js +32 -0
  121. package/library/{core → impl}/client.d.ts +16 -13
  122. package/library/impl/client.d.ts.map +1 -0
  123. package/library/{core → impl}/client.js +251 -330
  124. package/library/{core → impl}/request.d.ts.map +1 -1
  125. package/library/{core → impl}/response.d.ts +5 -10
  126. package/library/impl/response.d.ts.map +1 -0
  127. package/library/{core → impl}/response.js +113 -155
  128. package/library/{core → impl}/server.d.ts +22 -55
  129. package/library/impl/server.d.ts.map +1 -0
  130. package/library/impl/server.js +575 -0
  131. package/library/index.d.ts +13 -6
  132. package/library/index.d.ts.map +1 -1
  133. package/library/index.js +16 -16
  134. package/library/message/ack.d.ts +15 -0
  135. package/library/message/ack.d.ts.map +1 -0
  136. package/library/message/ack.js +33 -0
  137. package/library/message/channel-cache.d.ts +26 -0
  138. package/library/message/channel-cache.d.ts.map +1 -0
  139. package/library/message/channel-cache.js +115 -0
  140. package/library/message/channel.d.ts +53 -6
  141. package/library/message/channel.d.ts.map +1 -1
  142. package/library/message/channel.js +94 -8
  143. package/library/message/dispatcher.d.ts +7 -0
  144. package/library/message/dispatcher.d.ts.map +1 -1
  145. package/library/message/dispatcher.js +89 -76
  146. package/library/stream/error.d.ts +24 -0
  147. package/library/stream/error.d.ts.map +1 -0
  148. package/library/stream/error.js +29 -0
  149. package/library/stream/index.d.ts +4 -1
  150. package/library/stream/index.d.ts.map +1 -1
  151. package/library/stream/index.js +7 -4
  152. package/library/stream/readable-stream.d.ts.map +1 -1
  153. package/library/stream/readable-stream.js +46 -10
  154. package/library/stream/stream-core.d.ts.map +1 -1
  155. package/library/stream/stream-core.js +6 -1
  156. package/library/stream/writable-stream.d.ts.map +1 -1
  157. package/library/stream/writable-stream.js +99 -28
  158. package/library/types/index.d.ts +15 -19
  159. package/library/types/index.d.ts.map +1 -1
  160. package/library/utils/blob.d.ts +3 -0
  161. package/library/utils/blob.d.ts.map +1 -0
  162. package/library/utils/blob.js +22 -0
  163. package/library/utils/cache.d.ts +10 -20
  164. package/library/utils/cache.d.ts.map +1 -1
  165. package/library/utils/cache.js +25 -79
  166. package/library/utils/content-type.d.ts +13 -0
  167. package/library/utils/content-type.d.ts.map +1 -0
  168. package/library/utils/content-type.js +87 -0
  169. package/library/utils/debug.d.ts.map +1 -1
  170. package/library/utils/debug.js +155 -177
  171. package/library/utils/hooks.d.ts +30 -0
  172. package/library/utils/hooks.d.ts.map +1 -0
  173. package/library/utils/hooks.js +139 -0
  174. package/library/utils/id.d.ts +9 -0
  175. package/library/utils/id.d.ts.map +1 -0
  176. package/library/utils/id.js +21 -0
  177. package/library/utils/iframe.d.ts +5 -0
  178. package/library/utils/iframe.d.ts.map +1 -0
  179. package/library/utils/iframe.js +25 -0
  180. package/library/utils/index.d.ts +7 -34
  181. package/library/utils/index.d.ts.map +1 -1
  182. package/library/utils/index.js +58 -194
  183. package/library/utils/is.d.ts +2 -0
  184. package/library/utils/is.d.ts.map +1 -0
  185. package/library/utils/is.js +9 -0
  186. package/library/utils/logger.d.ts +13 -0
  187. package/library/utils/logger.d.ts.map +1 -0
  188. package/library/utils/logger.js +63 -0
  189. package/library/utils/promise.d.ts +2 -0
  190. package/library/utils/promise.d.ts.map +1 -0
  191. package/library/utils/promise.js +9 -0
  192. package/library/utils/window.d.ts +2 -0
  193. package/library/utils/window.d.ts.map +1 -0
  194. package/library/utils/window.js +38 -0
  195. package/package.json +49 -2
  196. package/react/package.json +2 -1
  197. package/esm/core/client-server.js +0 -294
  198. package/esm/core/server.js +0 -776
  199. package/library/core/client-server.d.ts +0 -97
  200. package/library/core/client-server.d.ts.map +0 -1
  201. package/library/core/client-server.js +0 -301
  202. package/library/core/client.d.ts.map +0 -1
  203. package/library/core/response.d.ts.map +0 -1
  204. package/library/core/server.d.ts.map +0 -1
  205. package/library/core/server.js +0 -781
  206. /package/esm/{core → impl}/request.js +0 -0
  207. /package/library/{core → impl}/request.d.ts +0 -0
  208. /package/library/{core → impl}/request.js +0 -0
package/QUICKSTART.CN.md CHANGED
@@ -220,9 +220,11 @@ server.on('/api/users/:id', (req, res) => {
220
220
  开启 trace 模式查看详细日志:
221
221
 
222
222
  ```typescript
223
+ import { LogLevel } from 'request-iframe';
224
+
223
225
  const client = requestIframeClient(iframe, {
224
226
  secretKey: 'my-app',
225
- trace: true // 开启调试日志
227
+ trace: LogLevel.INFO // 输出 info/warn/error(也可以用 true 开启 TRACE)
226
228
  });
227
229
 
228
230
  const server = requestIframeServer({
@@ -293,4 +295,4 @@ console.log(response.data.name); // TypeScript 知道这是 string
293
295
 
294
296
  - 查看 [README.CN.md](./README.CN.md) 了解完整 API(中文)
295
297
  - 查看 [README.md](./README.md) 了解完整 API(English)
296
- - 查看 [src/__tests__](./src/__tests__) 目录下的测试用例获取更多示例
298
+ - 查看 [`__tests__/`](./__tests__) 与 [`react/__tests__/`](./react/__tests__) 下的测试用例获取更多示例
package/QUICKSTART.md CHANGED
@@ -220,9 +220,11 @@ server.on('/api/users/:id', (req, res) => {
220
220
  Enable trace mode to view detailed logs:
221
221
 
222
222
  ```typescript
223
+ import { LogLevel } from 'request-iframe';
224
+
223
225
  const client = requestIframeClient(iframe, {
224
226
  secretKey: 'my-app',
225
- trace: true // Enable debug logs
227
+ trace: LogLevel.INFO // Enable info/warn/error logs (or use true for TRACE)
226
228
  });
227
229
 
228
230
  const server = requestIframeServer({
@@ -293,4 +295,4 @@ console.log(response.data.name); // TypeScript knows this is string
293
295
 
294
296
  - View [README.md](./README.md) for complete API documentation (English)
295
297
  - View [README.CN.md](./README.CN.md) for complete API documentation (中文)
296
- - Check [src/__tests__](./src/__tests__) directory for more examples from test cases
298
+ - Check [`__tests__/`](./__tests__) and [`react/__tests__/`](./react/__tests__) for more examples from test cases
package/README.CN.md CHANGED
@@ -76,6 +76,7 @@
76
76
  - 🔒 **消息隔离** - secretKey 机制避免多实例消息串线
77
77
  - 📁 **文件传输** - 支持文件通过流方式传输(Client↔Server)
78
78
  - 🌊 **流式传输** - 支持大文件分块传输,支持异步迭代器
79
+ - 🧾 **分级日志** - 默认只输出 warn/error,可通过 `trace` 设置日志等级与调试日志
79
80
  - 🌍 **多语言** - 错误消息可自定义,便于国际化
80
81
  - ✅ **协议版本** - 内置版本控制,便于升级兼容
81
82
 
@@ -93,6 +94,32 @@ pnpm add request-iframe
93
94
 
94
95
  **TypeScript**: 内置完整类型定义,无需安装 `@types/request-iframe`
95
96
 
97
+ ## CDN(UMD bundle)
98
+
99
+ 本项目也支持构建 **可直接用 `<script>` 引入的 UMD bundle**(核心 + React hooks),方便放到 CDN 上。
100
+
101
+ - 核心 bundle 输出:`cdn/request-iframe.umd(.min).js` → 全局变量 `RequestIframe`
102
+ - React bundle 输出:`cdn/request-iframe-react.umd(.min).js` → 全局变量 `RequestIframeReact`
103
+ - 依赖 `React` 全局变量(即 `react` 的 UMD 版本)
104
+ - 依赖 `RequestIframe` 全局变量(先加载核心 bundle)
105
+
106
+ 示例(使用 unpkg):
107
+
108
+ ```html
109
+ <!-- 核心 -->
110
+ <script src="https://unpkg.com/request-iframe@latest/cdn/request-iframe.umd.min.js"></script>
111
+
112
+ <!-- React(可选) -->
113
+ <script src="https://unpkg.com/react@latest/umd/react.production.min.js"></script>
114
+ <script src="https://unpkg.com/request-iframe@latest/cdn/request-iframe-react.umd.min.js"></script>
115
+
116
+ <script>
117
+ const { requestIframeClient, requestIframeServer, requestIframeEndpoint } = RequestIframe;
118
+ // React hooks 在 RequestIframeReact 上(例如 RequestIframeReact.useClient)
119
+ console.log(!!requestIframeClient, !!requestIframeServer, !!requestIframeEndpoint);
120
+ <\/script>
121
+ ```
122
+
96
123
  ## 快速开始
97
124
 
98
125
  ### 1. 父页面(Client 端)
@@ -130,6 +157,11 @@ server.on('/api/getUserInfo', (req, res) => {
130
157
 
131
158
  > 💡 **提示**: 更多快速上手指南请查看 [QUICKSTART.CN.md](./QUICKSTART.CN.md) 或 [QUICKSTART.md](./QUICKSTART.md) (English)
132
159
 
160
+ ## 该用哪个 API?
161
+
162
+ - **优先使用 `requestIframeClient()` + `requestIframeServer()`**:适用于主要是单向通信(父页 → iframe),并且你希望把“发送请求”和“处理请求”职责明确分开。
163
+ - **优先使用 `requestIframeEndpoint()`**:适用于需要 **双向通信**(双方都需要 `send()` + `on()/use()/map()`),或者你希望用一个门面对象更方便地串起全链路做调试。
164
+
133
165
  ---
134
166
 
135
167
  ## 实现原理
@@ -874,7 +906,7 @@ interface WritableStreamOptions {
874
906
 
875
907
  **pull/ack 协议(新增,默认启用):**
876
908
  - 读侧会自动发送 `stream_pull` 请求更多 chunk;写侧只会在收到 `stream_pull` 后才继续发送 `stream_data`,实现真正的背压(按需拉取)。
877
- - 断连检测不依赖 `stream_ack`,而是通过 `streamTimeout + 心跳(isConnect)` 来实现。
909
+ - 断连检测不依赖“逐帧确认专用消息类型”,而是通过 `streamTimeout + 心跳(isConnect)` 来实现。
878
910
 
879
911
  **consume 默认行为(变更):**
880
912
  - `for await (const chunk of stream)` 默认会 **消费并丢弃已迭代过的 chunk**(`consume: true`),避免长流场景内存无限增长。
@@ -913,17 +945,21 @@ server.on('/api/important', async (req, res) => {
913
945
 
914
946
  ### 追踪模式
915
947
 
916
- 开启追踪模式可以在控制台查看详细的通信日志:
948
+ 默认情况下,request-iframe 只会输出 **warn/error** 日志(避免生产环境控制台过于吵闹)。
949
+
950
+ 开启追踪模式(或设置日志等级)可以在控制台查看更详细的通信日志:
917
951
 
918
952
  ```typescript
953
+ import { LogLevel } from 'request-iframe';
954
+
919
955
  const client = requestIframeClient(iframe, {
920
956
  secretKey: 'demo',
921
- trace: true
957
+ trace: true // 等价于 LogLevel.TRACE
922
958
  });
923
959
 
924
960
  const server = requestIframeServer({
925
961
  secretKey: 'demo',
926
- trace: true
962
+ trace: LogLevel.INFO // 输出 info/warn/error(比 trace 更克制)
927
963
  });
928
964
 
929
965
  // 控制台输出:
@@ -932,6 +968,14 @@ const server = requestIframeServer({
932
968
  // [request-iframe] [INFO] ✅ Request Success { status: 200, data: {...} }
933
969
  ```
934
970
 
971
+ `trace` 支持:
972
+ - `true` / `false`
973
+ - `'trace' | 'info' | 'warn' | 'error' | 'silent'`(或 `LogLevel.*`)
974
+
975
+ 说明:
976
+ - 当 `trace` 为 `LogLevel.TRACE` / `LogLevel.INFO` 时,库会额外挂载内置的调试拦截器/监听器,以输出更丰富的 request/response 日志。
977
+ - 当 `trace` 为 `LogLevel.WARN` / `LogLevel.ERROR` / `LogLevel.SILENT` 时,只影响日志输出等级(不会额外挂载调试拦截器)。
978
+
935
979
  ### 多语言支持
936
980
 
937
981
  ```typescript
@@ -962,7 +1006,7 @@ setMessages({
962
1006
  |------|------|------|
963
1007
  | `target` | `HTMLIFrameElement \| Window` | 目标 iframe 元素或 window 对象 |
964
1008
  | `options.secretKey` | `string` | 消息隔离标识(可选) |
965
- | `options.trace` | `boolean` | 是否开启追踪模式(可选) |
1009
+ | `options.trace` | `boolean \| 'trace' \| 'info' \| 'warn' \| 'error' \| 'silent'` | trace/日志等级(可选)。默认只输出 warn/error |
966
1010
  | `options.targetOrigin` | `string` | 覆盖 postMessage 的 targetOrigin(可选)。当 `target` 是 `Window` 时默认 `*`;当 `target` 是 iframe 时默认取 `iframe.src` 的 origin。 |
967
1011
  | `options.ackTimeout` | `number` | 全局默认 ACK 确认超时(ms),默认 1000 |
968
1012
  | `options.timeout` | `number` | 全局默认请求超时(ms),默认 5000 |
@@ -1064,7 +1108,7 @@ await client.send('/api/longTask', {}, {
1064
1108
  | 参数 | 类型 | 说明 |
1065
1109
  |------|------|------|
1066
1110
  | `options.secretKey` | `string` | 消息隔离标识(可选) |
1067
- | `options.trace` | `boolean` | 是否开启追踪模式(可选) |
1111
+ | `options.trace` | `boolean \| 'trace' \| 'info' \| 'warn' \| 'error' \| 'silent'` | trace/日志等级(可选)。默认只输出 warn/error |
1068
1112
  | `options.ackTimeout` | `number` | 等待客户端确认超时(ms),默认 1000 |
1069
1113
  | `options.maxConcurrentRequestsPerClient` | `number` | 每个客户端的最大并发 in-flight 请求数(按 origin + creatorId 维度),默认 Infinity |
1070
1114
  | `options.allowedOrigins` | `string \| RegExp \| Array<string \| RegExp>` | 接收消息的 origin 白名单(可选,生产环境强烈建议配置) |
@@ -1072,6 +1116,65 @@ await client.send('/api/longTask', {}, {
1072
1116
 
1073
1117
  **返回值:** `RequestIframeServer`
1074
1118
 
1119
+ ### requestIframeEndpoint(target, options?)
1120
+
1121
+ 创建一个 **endpoint 门面**(client + server)并绑定到某个对端窗口/iframe。
1122
+
1123
+ 它可以:
1124
+ - **向对端发送请求**:`endpoint.send(...)`
1125
+ - **处理对端发来的请求**:`endpoint.on(...)` / `endpoint.use(...)` / `endpoint.map(...)`
1126
+
1127
+ 说明:
1128
+ - 内部的 client/server 是 **懒创建** 的(只有首次使用发送/注册 handler 等能力时才会创建)。
1129
+ - 如果传了 `options.id`,它会作为 client+server 的共享 id;不传则会自动生成一个。
1130
+ - `options.trace` 与 client/server 一致,推荐用 `LogLevel.*` 来配置日志等级。
1131
+
1132
+ 示例(使用 endpoint 做双向通信,推荐):
1133
+
1134
+ ```typescript
1135
+ import { requestIframeEndpoint, LogLevel } from 'request-iframe';
1136
+
1137
+ // 父页面(持有 iframe 元素)
1138
+ const iframe = document.querySelector('iframe')!;
1139
+ const parentEndpoint = requestIframeEndpoint(iframe, {
1140
+ secretKey: 'demo',
1141
+ trace: LogLevel.INFO
1142
+ });
1143
+ parentEndpoint.on('/notify', (req, res) => res.send({ ok: true, echo: req.body }));
1144
+
1145
+ // iframe 页面(持有 window.parent)
1146
+ const iframeEndpoint = requestIframeEndpoint(window.parent, {
1147
+ secretKey: 'demo',
1148
+ targetOrigin: 'https://parent.example.com',
1149
+ trace: true
1150
+ });
1151
+ iframeEndpoint.on('/api/ping', (req, res) => res.send({ ok: true }));
1152
+
1153
+ // 任意一侧都可以 send + handle
1154
+ await parentEndpoint.send('/api/ping', { from: 'parent' });
1155
+ await iframeEndpoint.send('/notify', { from: 'iframe' });
1156
+ ```
1157
+
1158
+ 生产环境推荐配置(模板):
1159
+
1160
+ ```typescript
1161
+ import { requestIframeEndpoint, LogLevel } from 'request-iframe';
1162
+
1163
+ const secretKey = 'my-app';
1164
+ const iframe = document.querySelector('iframe')!;
1165
+ const targetOrigin = new URL(iframe.src).origin;
1166
+
1167
+ const endpoint = requestIframeEndpoint(iframe, {
1168
+ secretKey,
1169
+ targetOrigin,
1170
+ allowedOrigins: [targetOrigin],
1171
+ // 防止异常/攻击导致消息爆炸(按需设置)
1172
+ maxConcurrentRequestsPerClient: 50,
1173
+ // 日志:默认只输出 warn/error;调试时可切到 LogLevel.INFO / LogLevel.TRACE
1174
+ trace: LogLevel.WARN
1175
+ });
1176
+ ```
1177
+
1075
1178
  ### Client API
1076
1179
 
1077
1180
  #### client.send(path, body?, options?)
@@ -1672,7 +1775,10 @@ import {
1672
1775
  // 多语言消息
1673
1776
  Messages,
1674
1777
  setMessages,
1675
- formatMessage
1778
+ formatMessage,
1779
+
1780
+ // 日志等级
1781
+ LogLevel
1676
1782
  } from 'request-iframe';
1677
1783
  ```
1678
1784
 
@@ -1763,7 +1869,11 @@ const server = requestIframeServer();
1763
1869
 
1764
1870
  ### 4. Server 可以主动推送消息吗?
1765
1871
 
1766
- request-iframe 是请求-响应模式,Server 不能主动推送。如需双向通信,可以让 iframe 内也创建 Client:
1872
+ request-iframe 是请求-响应模式,Server 本身不能“主动推送”。
1873
+
1874
+ 如需双向通信,有两种做法:
1875
+ - iframe 内创建一个反向的 Client(传统做法)
1876
+ - 双方都使用 `requestIframeEndpoint()`(推荐),一个对象同时具备 **send + handle**
1767
1877
 
1768
1878
  ```typescript
1769
1879
  // iframe 内
@@ -1776,10 +1886,11 @@ await client.send('/notify', { event: 'data-changed' });
1776
1886
 
1777
1887
  ### 5. 如何调试通信问题?
1778
1888
 
1779
- 1. **开启 trace 模式**:查看详细的通信日志
1780
- 2. **检查 secretKey**:确保 Client 和 Server 使用相同的 secretKey
1889
+ 1. **按日志等级开启输出**:默认只输出 warn/error;建议设置 `trace: LogLevel.INFO`(或 `trace: true`)来输出更详细的通信日志
1890
+ 2. **检查 secretKey**:确保双方使用相同的 `secretKey`
1781
1891
  3. **检查 iframe 加载**:确保 iframe 已完全加载
1782
- 4. **检查控制台**:查看是否有跨域错误
1892
+ 4. **检查 origin 约束**:尽量设置严格的 `targetOrigin`,并配置 `allowedOrigins` / `validateOrigin`,避免因为校验失败导致消息被忽略
1893
+ 5. **考虑使用 `requestIframeEndpoint()`**:把双向(send + handle)能力合在一个对象里,更容易串起完整链路做排查
1783
1894
 
1784
1895
  ### 6. 支持哪些浏览器?
1785
1896
 
@@ -1833,27 +1944,10 @@ client.interceptors.response.use(
1833
1944
  );
1834
1945
  ```
1835
1946
 
1836
- ### 9. 如何调试通信问题?
1837
-
1838
- 1. **开启 trace 模式**:在创建 client/server 时设置 `trace: true`
1839
- 2. **检查控制台**:查看详细的通信日志
1840
- 3. **验证 secretKey**:确保 client 和 server 使用相同的 secretKey
1841
- 4. **检查 iframe 加载**:确保 iframe 已完全加载后再发送请求
1842
- 5. **使用 `isConnect()`**:先检测连接是否正常
1947
+ ### 9. trace/日志等级怎么用?
1843
1948
 
1844
- ```typescript
1845
- // 开启调试模式
1846
- const client = requestIframeClient(iframe, {
1847
- secretKey: 'my-app',
1848
- trace: true // 开启详细日志
1849
- });
1850
-
1851
- // 检测连接
1852
- const connected = await client.isConnect();
1853
- if (!connected) {
1854
- console.error('无法连接到 iframe');
1855
- }
1856
- ```
1949
+ - 推荐优先使用常量:`trace: LogLevel.INFO` / `trace: LogLevel.TRACE`
1950
+ - 如果你在做双向排查,推荐使用 `requestIframeEndpoint()` 并把 trace 打开(这样 send/handle 都在同一对象上更直观)
1857
1951
 
1858
1952
  ### 10. 性能如何?
1859
1953
 
@@ -1927,14 +2021,16 @@ yarn build
1927
2021
  request-iframe/
1928
2022
  ├── src/
1929
2023
  │ ├── api/ # 对外 API(client.ts, server.ts)
1930
- │ ├── core/ # 核心实现(client, server, request, response)
2024
+ │ ├── impl/ # 实现层(client, server, request, response)
2025
+ │ ├── endpoint/ # endpoint 基础设施(hub/inbox/outbox + stream/heartbeat 等)
1931
2026
  │ ├── message/ # 消息通信层(channel, dispatcher)
1932
2027
  │ ├── stream/ # 流式传输实现
1933
2028
  │ ├── interceptors/ # 拦截器实现
1934
2029
  │ ├── utils/ # 工具函数
1935
2030
  │ ├── constants/ # 常量定义
1936
2031
  │ ├── types/ # TypeScript 类型定义
1937
- │ └── __tests__/ # 测试文件
2032
+ ├── __tests__/ # 测试文件(Jest)
2033
+ ├── react/__tests__/ # React hooks 测试
1938
2034
  ├── library/ # 构建输出
1939
2035
  ├── coverage/ # 测试覆盖率报告
1940
2036
  ├── jest.config.js # Jest 配置
package/README.md CHANGED
@@ -76,6 +76,7 @@ In micro-frontend, iframe nesting, and popup window scenarios, cross-page commun
76
76
  - 🔒 **Message Isolation** - secretKey mechanism prevents message cross-talk between multiple instances
77
77
  - 📁 **File Transfer** - File transfer via streams (client↔server)
78
78
  - 🌊 **Streaming** - Support for large file chunked transfer, supports async iterators
79
+ - 🧾 **Leveled Logging** - Warn/Error logs enabled by default; can be configured via `trace` level
79
80
  - 🌍 **Internationalization** - Error messages can be customized for i18n
80
81
  - ✅ **Protocol Versioning** - Built-in version control for upgrade compatibility
81
82
 
@@ -93,6 +94,30 @@ pnpm add request-iframe
93
94
 
94
95
  **TypeScript**: Built-in complete type definitions, no need to install `@types/request-iframe`
95
96
 
97
+ ## CDN (UMD bundles)
98
+
99
+ This repo also builds **script-tag friendly UMD bundles** (core + react hooks) that can be hosted on a CDN.
100
+
101
+ - Core bundle output: `cdn/request-iframe.umd(.min).js` → global `RequestIframe`
102
+ - React bundle output: `cdn/request-iframe-react.umd(.min).js` → global `RequestIframeReact` (requires `React` global and `RequestIframe` global)
103
+
104
+ Example (using unpkg):
105
+
106
+ ```html
107
+ <!-- Core -->
108
+ <script src="https://unpkg.com/request-iframe@latest/cdn/request-iframe.umd.min.js"></script>
109
+
110
+ <!-- React (optional) -->
111
+ <script src="https://unpkg.com/react@latest/umd/react.production.min.js"></script>
112
+ <script src="https://unpkg.com/request-iframe@latest/cdn/request-iframe-react.umd.min.js"></script>
113
+
114
+ <script>
115
+ const { requestIframeClient, requestIframeServer, requestIframeEndpoint } = RequestIframe;
116
+ // React hooks are available on RequestIframeReact (e.g. RequestIframeReact.useClient)
117
+ console.log(!!requestIframeClient, !!requestIframeServer, !!requestIframeEndpoint);
118
+ <\/script>
119
+ ```
120
+
96
121
  ## Quick Start
97
122
 
98
123
  ### 1. Parent Page (Client Side)
@@ -130,6 +155,11 @@ That's it! 🎉
130
155
 
131
156
  > 💡 **Tip**: For more quick start guides, see [QUICKSTART.md](./QUICKSTART.md) or [QUICKSTART.CN.md](./QUICKSTART.CN.md) (中文)
132
157
 
158
+ ## Which API should I use?
159
+
160
+ - **Use `requestIframeClient()` + `requestIframeServer()`** when communication is mostly one-way (parent → iframe), and you prefer a clear separation between request sender and handler.
161
+ - **Use `requestIframeEndpoint()`** when you need **bidirectional** communication (both sides need `send()` + `on()/use()/map()`), or when you want a single façade object to debug a full flow more easily.
162
+
133
163
  ---
134
164
 
135
165
  ## Use Cases
@@ -834,7 +864,7 @@ server.on('/api/uploadStream', async (req, res) => {
834
864
 
835
865
  **Pull/Ack protocol (default):**
836
866
  - Writer only sends `stream_data` when it has received `stream_pull`, enabling real backpressure.
837
- - Disconnect detection does not rely on `stream_ack`, but uses `streamTimeout + heartbeat(isConnect)`.
867
+ - Disconnect detection does not rely on a dedicated per-frame ack message type, but uses `streamTimeout + heartbeat(isConnect)`.
838
868
 
839
869
  **consume default change:**
840
870
  - `for await (const chunk of response.stream)` defaults to **consume and drop** already iterated chunks (`consume: true`) to prevent unbounded memory growth for long streams.
@@ -872,17 +902,21 @@ server.on('/api/important', async (req, res) => {
872
902
 
873
903
  ### Trace Mode
874
904
 
875
- Enable trace mode to view detailed communication logs in console:
905
+ By default, request-iframe only prints **warn/error** logs (to avoid noisy console in production).
906
+
907
+ Enable trace mode (or set a log level) to view detailed communication logs:
876
908
 
877
909
  ```typescript
910
+ import { LogLevel } from 'request-iframe';
911
+
878
912
  const client = requestIframeClient(iframe, {
879
913
  secretKey: 'demo',
880
- trace: true
914
+ trace: true // equivalent to LogLevel.TRACE
881
915
  });
882
916
 
883
917
  const server = requestIframeServer({
884
918
  secretKey: 'demo',
885
- trace: true
919
+ trace: LogLevel.INFO // enable info/warn/error logs (less verbose than trace)
886
920
  });
887
921
 
888
922
  // Console output:
@@ -891,6 +925,14 @@ const server = requestIframeServer({
891
925
  // [request-iframe] [INFO] ✅ Request Success { status: 200, data: {...} }
892
926
  ```
893
927
 
928
+ `trace` supports:
929
+ - `true` / `false`
930
+ - `'trace' | 'info' | 'warn' | 'error' | 'silent'` (or `LogLevel.*`)
931
+
932
+ Notes:
933
+ - When `trace` is `LogLevel.TRACE` or `LogLevel.INFO`, the library will also attach built-in debug interceptors/listeners for richer request/response logs.
934
+ - When `trace` is `LogLevel.WARN` / `LogLevel.ERROR` / `LogLevel.SILENT`, it only affects log output level (no extra debug interceptors attached).
935
+
894
936
  ### Internationalization
895
937
 
896
938
  ```typescript
@@ -921,7 +963,7 @@ Create a Client instance.
921
963
  |-----------|------|-------------|
922
964
  | `target` | `HTMLIFrameElement \| Window` | Target iframe element or window object |
923
965
  | `options.secretKey` | `string` | Message isolation identifier (optional) |
924
- | `options.trace` | `boolean` | Whether to enable trace mode (optional) |
966
+ | `options.trace` | `boolean \| 'trace' \| 'info' \| 'warn' \| 'error' \| 'silent'` | Trace/log level (optional). Default logs are warn/error only |
925
967
  | `options.targetOrigin` | `string` | Override postMessage targetOrigin for sending (optional). If `target` is a `Window`, default is `*`. |
926
968
  | `options.ackTimeout` | `number` | Global default ACK acknowledgment timeout (ms), default 1000 |
927
969
  | `options.timeout` | `number` | Global default request timeout (ms), default 5000 |
@@ -1006,7 +1048,7 @@ Create a Server instance.
1006
1048
  | Parameter | Type | Description |
1007
1049
  |-----------|------|-------------|
1008
1050
  | `options.secretKey` | `string` | Message isolation identifier (optional) |
1009
- | `options.trace` | `boolean` | Whether to enable trace mode (optional) |
1051
+ | `options.trace` | `boolean \| 'trace' \| 'info' \| 'warn' \| 'error' \| 'silent'` | Trace/log level (optional). Default logs are warn/error only |
1010
1052
  | `options.ackTimeout` | `number` | Wait for client acknowledgment timeout (ms), default 1000 |
1011
1053
  | `options.maxConcurrentRequestsPerClient` | `number` | Max concurrent in-flight requests per client (per origin + creatorId). Default Infinity |
1012
1054
  | `options.allowedOrigins` | `string \| RegExp \| Array<string \| RegExp>` | Allowlist for incoming message origins (optional, recommended for production) |
@@ -1014,6 +1056,65 @@ Create a Server instance.
1014
1056
 
1015
1057
  **Returns:** `RequestIframeServer`
1016
1058
 
1059
+ ### requestIframeEndpoint(target, options?)
1060
+
1061
+ Create an **endpoint facade** (client + server) for a peer window/iframe.
1062
+
1063
+ It can:
1064
+ - **send requests** to the peer: `endpoint.send(...)`
1065
+ - **handle requests** from the peer: `endpoint.on(...)`, `endpoint.use(...)`, `endpoint.map(...)`
1066
+
1067
+ Notes:
1068
+ - Client and server instances are **lazily created** (only when you first access send/handlers APIs).
1069
+ - `options.id` (if provided) becomes the shared ID for both sides (client + server); otherwise a random one is generated.
1070
+ - `options.trace` follows the same leveled logging rules as client/server (`LogLevel.*` recommended).
1071
+
1072
+ Example (bidirectional via endpoint, recommended):
1073
+
1074
+ ```typescript
1075
+ import { requestIframeEndpoint, LogLevel } from 'request-iframe';
1076
+
1077
+ // Parent page (has iframe element)
1078
+ const iframe = document.querySelector('iframe')!;
1079
+ const parentEndpoint = requestIframeEndpoint(iframe, {
1080
+ secretKey: 'demo',
1081
+ trace: LogLevel.INFO
1082
+ });
1083
+ parentEndpoint.on('/notify', (req, res) => res.send({ ok: true, echo: req.body }));
1084
+
1085
+ // Iframe page (has window.parent)
1086
+ const iframeEndpoint = requestIframeEndpoint(window.parent, {
1087
+ secretKey: 'demo',
1088
+ targetOrigin: 'https://parent.example.com',
1089
+ trace: true
1090
+ });
1091
+ iframeEndpoint.on('/api/ping', (req, res) => res.send({ ok: true }));
1092
+
1093
+ // Either side can now send + handle
1094
+ await parentEndpoint.send('/api/ping', { from: 'parent' });
1095
+ await iframeEndpoint.send('/notify', { from: 'iframe' });
1096
+ ```
1097
+
1098
+ Production configuration template (recommended):
1099
+
1100
+ ```typescript
1101
+ import { requestIframeEndpoint, LogLevel } from 'request-iframe';
1102
+
1103
+ const secretKey = 'my-app';
1104
+ const iframe = document.querySelector('iframe')!;
1105
+ const targetOrigin = new URL(iframe.src).origin;
1106
+
1107
+ const endpoint = requestIframeEndpoint(iframe, {
1108
+ secretKey,
1109
+ targetOrigin,
1110
+ allowedOrigins: [targetOrigin],
1111
+ // Mitigate message explosion (tune as needed)
1112
+ maxConcurrentRequestsPerClient: 50,
1113
+ // Logs: default is warn/error; choose info for debugging
1114
+ trace: LogLevel.WARN
1115
+ });
1116
+ ```
1117
+
1017
1118
  ### Client API
1018
1119
 
1019
1120
  #### client.send(path, body?, options?)
@@ -1591,7 +1692,11 @@ Just ensure both sides use the same `secretKey`.
1591
1692
 
1592
1693
  ### 4. Can Server actively push messages?
1593
1694
 
1594
- request-iframe is request-response mode, Server cannot actively push. For bidirectional communication, you can create a Client inside the iframe:
1695
+ request-iframe is request-response mode, Server cannot actively push by itself.
1696
+
1697
+ For bidirectional communication, you have 2 options:
1698
+ - Create a reverse `client` inside the iframe (traditional way)
1699
+ - Use `requestIframeEndpoint()` on both sides (recommended) so each side has **send + handle** in one object
1595
1700
 
1596
1701
  ```typescript
1597
1702
  // Inside iframe
@@ -1604,10 +1709,11 @@ await client.send('/notify', { event: 'data-changed' });
1604
1709
 
1605
1710
  ### 5. How to debug communication issues?
1606
1711
 
1607
- 1. **Enable trace mode**: View detailed communication logs
1712
+ 1. **Enable logs with levels**: by default only warn/error logs are printed; enable `trace: LogLevel.INFO` (or `trace: true`) to see detailed logs
1608
1713
  2. **Check secretKey**: Ensure Client and Server use the same secretKey
1609
1714
  3. **Check iframe loading**: Ensure iframe is fully loaded
1610
- 4. **Check console**: Check for cross-origin errors
1715
+ 4. **Check origin constraints**: prefer setting strict `targetOrigin` and configure `allowedOrigins` / `validateOrigin`
1716
+ 5. **Consider using `requestIframeEndpoint()`**: it unifies both directions (send + handle) and makes it easier to debug flows in one place
1611
1717
 
1612
1718
  ---
1613
1719
 
@@ -1659,12 +1765,7 @@ yarn build
1659
1765
 
1660
1766
  ### Test Coverage
1661
1767
 
1662
- The project currently has **76.88%** test coverage, meeting production requirements:
1663
-
1664
- - **Statement Coverage**: 76.88%
1665
- - **Branch Coverage**: 64.13%
1666
- - **Function Coverage**: 75%
1667
- - **Line Coverage**: 78.71%
1768
+ The project maintains **high test coverage** and CI coverage reports (see badges at the top of this README).
1668
1769
 
1669
1770
  Coverage reports are generated in the `coverage/` directory, view detailed coverage report via `coverage/index.html`.
1670
1771