request-iframe 0.1.1 → 0.2.1
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/QUICKSTART.CN.md +4 -2
- package/QUICKSTART.md +4 -2
- package/README.CN.md +129 -33
- package/README.md +116 -15
- package/cdn/request-iframe-react.umd.js +3354 -0
- package/cdn/request-iframe-react.umd.js.map +1 -0
- package/cdn/request-iframe-react.umd.min.js +2 -0
- package/cdn/request-iframe-react.umd.min.js.map +1 -0
- package/cdn/request-iframe.umd.js +19761 -0
- package/cdn/request-iframe.umd.js.map +1 -0
- package/cdn/request-iframe.umd.min.js +4 -0
- package/cdn/request-iframe.umd.min.js.map +1 -0
- package/esm/api/client.js +29 -21
- package/esm/api/endpoint.js +229 -0
- package/esm/api/server.js +16 -8
- package/esm/constants/debug.js +17 -0
- package/esm/constants/index.js +84 -67
- package/esm/constants/log.js +11 -0
- package/esm/constants/messages.js +3 -0
- package/esm/constants/warn-once.js +15 -0
- package/esm/endpoint/facade.js +390 -0
- package/esm/endpoint/heartbeat/heartbeat.js +60 -0
- package/esm/endpoint/heartbeat/ping.js +20 -0
- package/esm/endpoint/index.js +13 -0
- package/esm/endpoint/infra/hub.js +316 -0
- package/esm/endpoint/infra/inbox.js +232 -0
- package/esm/endpoint/infra/outbox.js +408 -0
- package/esm/endpoint/stream/dispatcher.js +58 -0
- package/esm/endpoint/stream/errors.js +27 -0
- package/esm/endpoint/stream/factory.js +76 -0
- package/esm/endpoint/stream/file-auto-resolve.js +34 -0
- package/esm/endpoint/stream/file-writable.js +105 -0
- package/esm/endpoint/stream/handler.js +26 -0
- package/esm/{core → impl}/client.js +240 -317
- package/esm/{core → impl}/response.js +113 -155
- package/esm/impl/server.js +568 -0
- package/esm/index.js +13 -6
- package/esm/message/ack.js +27 -0
- package/esm/message/channel-cache.js +108 -0
- package/esm/message/channel.js +90 -4
- package/esm/message/dispatcher.js +115 -75
- package/esm/stream/error.js +22 -0
- package/esm/stream/index.js +3 -1
- package/esm/stream/readable-stream.js +45 -9
- package/esm/stream/stream-core.js +7 -2
- package/esm/stream/writable-stream.js +97 -26
- package/esm/utils/blob.js +16 -0
- package/esm/utils/cache.js +25 -76
- package/esm/utils/content-type.js +81 -0
- package/esm/utils/debug.js +156 -179
- package/esm/utils/hooks.js +130 -0
- package/esm/utils/id.js +14 -0
- package/esm/utils/iframe.js +20 -0
- package/esm/utils/index.js +11 -163
- package/esm/utils/is.js +3 -0
- package/esm/utils/logger.js +55 -0
- package/esm/utils/promise.js +3 -0
- package/esm/utils/window.js +31 -0
- package/library/api/client.d.ts.map +1 -1
- package/library/api/client.js +30 -22
- package/library/api/endpoint.d.ts +23 -0
- package/library/api/endpoint.d.ts.map +1 -0
- package/library/api/endpoint.js +235 -0
- package/library/api/server.d.ts +4 -1
- package/library/api/server.d.ts.map +1 -1
- package/library/api/server.js +16 -8
- package/library/constants/debug.d.ts +18 -0
- package/library/constants/debug.d.ts.map +1 -0
- package/library/constants/debug.js +23 -0
- package/library/constants/index.d.ts +22 -2
- package/library/constants/index.d.ts.map +1 -1
- package/library/constants/index.js +110 -67
- package/library/constants/log.d.ts +12 -0
- package/library/constants/log.d.ts.map +1 -0
- package/library/constants/log.js +17 -0
- package/library/constants/messages.d.ts +3 -0
- package/library/constants/messages.d.ts.map +1 -1
- package/library/constants/messages.js +3 -0
- package/library/constants/warn-once.d.ts +12 -0
- package/library/constants/warn-once.d.ts.map +1 -0
- package/library/constants/warn-once.js +22 -0
- package/library/endpoint/facade.d.ts +238 -0
- package/library/endpoint/facade.d.ts.map +1 -0
- package/library/endpoint/facade.js +398 -0
- package/library/endpoint/heartbeat/heartbeat.d.ts +34 -0
- package/library/endpoint/heartbeat/heartbeat.d.ts.map +1 -0
- package/library/endpoint/heartbeat/heartbeat.js +67 -0
- package/library/endpoint/heartbeat/ping.d.ts +18 -0
- package/library/endpoint/heartbeat/ping.d.ts.map +1 -0
- package/library/endpoint/heartbeat/ping.js +26 -0
- package/library/endpoint/index.d.ts +16 -0
- package/library/endpoint/index.d.ts.map +1 -0
- package/library/endpoint/index.js +114 -0
- package/library/endpoint/infra/hub.d.ts +170 -0
- package/library/endpoint/infra/hub.d.ts.map +1 -0
- package/library/endpoint/infra/hub.js +323 -0
- package/library/endpoint/infra/inbox.d.ts +73 -0
- package/library/endpoint/infra/inbox.d.ts.map +1 -0
- package/library/endpoint/infra/inbox.js +239 -0
- package/library/endpoint/infra/outbox.d.ts +149 -0
- package/library/endpoint/infra/outbox.d.ts.map +1 -0
- package/library/endpoint/infra/outbox.js +415 -0
- package/library/endpoint/stream/dispatcher.d.ts +33 -0
- package/library/endpoint/stream/dispatcher.d.ts.map +1 -0
- package/library/endpoint/stream/dispatcher.js +66 -0
- package/library/endpoint/stream/errors.d.ts +20 -0
- package/library/endpoint/stream/errors.d.ts.map +1 -0
- package/library/endpoint/stream/errors.js +32 -0
- package/library/endpoint/stream/factory.d.ts +44 -0
- package/library/endpoint/stream/factory.d.ts.map +1 -0
- package/library/endpoint/stream/factory.js +82 -0
- package/library/endpoint/stream/file-auto-resolve.d.ts +26 -0
- package/library/endpoint/stream/file-auto-resolve.d.ts.map +1 -0
- package/library/endpoint/stream/file-auto-resolve.js +41 -0
- package/library/endpoint/stream/file-writable.d.ts +33 -0
- package/library/endpoint/stream/file-writable.d.ts.map +1 -0
- package/library/endpoint/stream/file-writable.js +115 -0
- package/library/endpoint/stream/handler.d.ts +20 -0
- package/library/endpoint/stream/handler.d.ts.map +1 -0
- package/library/endpoint/stream/handler.js +32 -0
- package/library/{core → impl}/client.d.ts +16 -13
- package/library/impl/client.d.ts.map +1 -0
- package/library/{core → impl}/client.js +251 -330
- package/library/{core → impl}/request.d.ts.map +1 -1
- package/library/{core → impl}/response.d.ts +5 -10
- package/library/impl/response.d.ts.map +1 -0
- package/library/{core → impl}/response.js +113 -155
- package/library/{core → impl}/server.d.ts +22 -55
- package/library/impl/server.d.ts.map +1 -0
- package/library/impl/server.js +575 -0
- package/library/index.d.ts +13 -6
- package/library/index.d.ts.map +1 -1
- package/library/index.js +16 -16
- package/library/message/ack.d.ts +15 -0
- package/library/message/ack.d.ts.map +1 -0
- package/library/message/ack.js +33 -0
- package/library/message/channel-cache.d.ts +26 -0
- package/library/message/channel-cache.d.ts.map +1 -0
- package/library/message/channel-cache.js +115 -0
- package/library/message/channel.d.ts +53 -6
- package/library/message/channel.d.ts.map +1 -1
- package/library/message/channel.js +94 -8
- package/library/message/dispatcher.d.ts +7 -0
- package/library/message/dispatcher.d.ts.map +1 -1
- package/library/message/dispatcher.js +116 -76
- package/library/stream/error.d.ts +24 -0
- package/library/stream/error.d.ts.map +1 -0
- package/library/stream/error.js +29 -0
- package/library/stream/index.d.ts +4 -1
- package/library/stream/index.d.ts.map +1 -1
- package/library/stream/index.js +7 -4
- package/library/stream/readable-stream.d.ts.map +1 -1
- package/library/stream/readable-stream.js +46 -10
- package/library/stream/stream-core.d.ts.map +1 -1
- package/library/stream/stream-core.js +6 -1
- package/library/stream/writable-stream.d.ts.map +1 -1
- package/library/stream/writable-stream.js +99 -28
- package/library/types/index.d.ts +15 -19
- package/library/types/index.d.ts.map +1 -1
- package/library/utils/blob.d.ts +3 -0
- package/library/utils/blob.d.ts.map +1 -0
- package/library/utils/blob.js +22 -0
- package/library/utils/cache.d.ts +10 -20
- package/library/utils/cache.d.ts.map +1 -1
- package/library/utils/cache.js +25 -79
- package/library/utils/content-type.d.ts +13 -0
- package/library/utils/content-type.d.ts.map +1 -0
- package/library/utils/content-type.js +87 -0
- package/library/utils/debug.d.ts.map +1 -1
- package/library/utils/debug.js +155 -177
- package/library/utils/hooks.d.ts +30 -0
- package/library/utils/hooks.d.ts.map +1 -0
- package/library/utils/hooks.js +139 -0
- package/library/utils/id.d.ts +9 -0
- package/library/utils/id.d.ts.map +1 -0
- package/library/utils/id.js +21 -0
- package/library/utils/iframe.d.ts +5 -0
- package/library/utils/iframe.d.ts.map +1 -0
- package/library/utils/iframe.js +25 -0
- package/library/utils/index.d.ts +7 -34
- package/library/utils/index.d.ts.map +1 -1
- package/library/utils/index.js +58 -194
- package/library/utils/is.d.ts +2 -0
- package/library/utils/is.d.ts.map +1 -0
- package/library/utils/is.js +9 -0
- package/library/utils/logger.d.ts +13 -0
- package/library/utils/logger.d.ts.map +1 -0
- package/library/utils/logger.js +63 -0
- package/library/utils/promise.d.ts +2 -0
- package/library/utils/promise.d.ts.map +1 -0
- package/library/utils/promise.js +9 -0
- package/library/utils/window.d.ts +2 -0
- package/library/utils/window.d.ts.map +1 -0
- package/library/utils/window.js +38 -0
- package/package.json +49 -2
- package/react/package.json +2 -1
- package/esm/core/client-server.js +0 -294
- package/esm/core/server.js +0 -776
- package/library/core/client-server.d.ts +0 -97
- package/library/core/client-server.d.ts.map +0 -1
- package/library/core/client-server.js +0 -301
- package/library/core/client.d.ts.map +0 -1
- package/library/core/response.d.ts.map +0 -1
- package/library/core/server.d.ts.map +0 -1
- package/library/core/server.js +0 -781
- /package/esm/{core → impl}/request.js +0 -0
- /package/library/{core → impl}/request.d.ts +0 -0
- /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:
|
|
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
|
-
- 查看 [
|
|
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:
|
|
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 [
|
|
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
|
-
-
|
|
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:
|
|
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
|
|
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.
|
|
1780
|
-
2. **检查 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
|
-
|
|
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
|
-
│ ├──
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|