chrome-in-iframe 1.0.1 → 2.0.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/CHANGELOG.md +304 -0
- package/CHANGELOG.zh-CN.md +203 -0
- package/LICENSE +15 -0
- package/README.md +105 -11
- package/README.zh-CN.md +108 -13
- package/dist/api.d.ts +4 -0
- package/dist/channel/channel.d.ts +1 -1
- package/dist/channel/deserializer.d.ts +3 -1
- package/dist/channel/listener.d.ts +3 -2
- package/dist/channel/sender.d.ts +1 -1
- package/dist/channel/serializer.d.ts +3 -1
- package/dist/channel/types.d.ts +34 -11
- package/dist/channel/utils.d.ts +1 -0
- package/dist/client/context.d.ts +5 -1
- package/dist/client/endpoint.d.ts +3 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1063 -315
- package/dist/log.d.ts +3 -0
- package/dist/processor/accessProperty.d.ts +3 -3
- package/dist/processor/invoke.d.ts +3 -3
- package/dist/processor/invokeCallback.d.ts +3 -3
- package/dist/processor/lifecycle.d.ts +3 -0
- package/package.json +19 -11
package/README.md
CHANGED
|
@@ -8,6 +8,20 @@ Bridge Chrome extension APIs from a Chrome extension page into an embedded ifram
|
|
|
8
8
|
|
|
9
9
|
This is useful when an extension page such as `options.html`, `popup.html`, or another `chrome-extension://...` page embeds an iframe, but the iframe itself cannot directly access Chrome extension APIs.
|
|
10
10
|
|
|
11
|
+
## Module Format
|
|
12
|
+
|
|
13
|
+
**This package is ESM-only.** It ships a single ECMAScript module and exposes no CommonJS entry point. Use it from an ESM project (Vite, Rollup, webpack 5+, Parcel 2+, modern bundlers, or native `<script type="module">`).
|
|
14
|
+
|
|
15
|
+
`require('chrome-in-iframe')` will not work.
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"type": "module"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If your tooling still emits CommonJS, configure it to leave `chrome-in-iframe` as an ESM external, or migrate the consuming project to ESM.
|
|
24
|
+
|
|
11
25
|
## Install
|
|
12
26
|
|
|
13
27
|
```bash
|
|
@@ -133,9 +147,9 @@ window.addEventListener('beforeunload', () => {
|
|
|
133
147
|
|
|
134
148
|
## Security Options
|
|
135
149
|
|
|
136
|
-
`targetOrigin` and `allowedOrigin` are optional.
|
|
150
|
+
`targetOrigin` and `allowedOrigin` are optional. When `targetOrigin` is not supplied, the library resolves it from `iframe.src` / `contentWindow.location.origin` (on the extension side) or from `document.referrer` / `location.ancestorOrigins` (on the iframe side); it only falls back to `'*'` when none of those are available. Incoming messages are checked against both the expected window source and, by default, the same origin resolved for `targetOrigin`.
|
|
137
151
|
|
|
138
|
-
> **Warning**:
|
|
152
|
+
> **Warning**: If origin auto-detection cannot resolve a concrete origin and falls back to `'*'`, incoming messages from the expected window source are allowed from any origin. For third-party iframes, navigable iframes, or any page from a different origin, pass explicit `targetOrigin` and `allowedOrigin`.
|
|
139
153
|
|
|
140
154
|
For production, pass origins when you know them.
|
|
141
155
|
|
|
@@ -160,6 +174,17 @@ const { chrome } = connectChromeInIframe({
|
|
|
160
174
|
});
|
|
161
175
|
```
|
|
162
176
|
|
|
177
|
+
## Data Types Across the Bridge
|
|
178
|
+
|
|
179
|
+
The bridge serializes `undefined`, `null`, all primitive types (including `bigint`, `NaN`, `Infinity`, `-0`), plain objects (string- and symbol-keyed), arrays, functions, `Error` (preserves `name`, `stack`, and `cause`), `Date`, `RegExp`, `Map`, and `Set`. Circular references throw.
|
|
180
|
+
|
|
181
|
+
A few inherent limitations of any RPC-style bridge:
|
|
182
|
+
|
|
183
|
+
- **Object identity is not preserved.** A `Date`, `Map`, `Set`, or plain object that crosses the bridge is reconstructed on the other side. `===` between the original and the round-tripped value is `false`.
|
|
184
|
+
- **Map / Set keyed on objects loses lookup.** If you put a `Date` (or any object) into a `Map` and send the `Map` across, `map.get(originalDate)` on the receiving side does **not** find it — the deserialized `Map` holds a different `Date` instance. Key on strings or numbers when the `Map` is meant to travel.
|
|
185
|
+
- **Non-global symbols cannot cross.** Use `Symbol.for(...)` or a well-known symbol; ad-hoc `Symbol('local')` throws on serialization.
|
|
186
|
+
- **Class prototypes are erased.** A `class Foo { ... }` instance arrives as a plain object with the same enumerable properties. `instanceof Foo` is `false`.
|
|
187
|
+
|
|
163
188
|
## Reading Properties
|
|
164
189
|
|
|
165
190
|
Chrome API methods can be called directly:
|
|
@@ -168,13 +193,54 @@ Chrome API methods can be called directly:
|
|
|
168
193
|
const tabs = await chrome.tabs.query({ active: true });
|
|
169
194
|
```
|
|
170
195
|
|
|
171
|
-
Readable properties should be read through `get()` or `$get()
|
|
196
|
+
Readable properties — anything that is not a function call — should be read through `get()` (returned from `connectChromeInIframe`) or `$get()` (available on every proxy node).
|
|
197
|
+
|
|
198
|
+
### Path Forms
|
|
199
|
+
|
|
200
|
+
`$get` / `get` accept three equivalent shapes for the path:
|
|
172
201
|
|
|
173
202
|
```ts
|
|
174
|
-
|
|
175
|
-
|
|
203
|
+
// 1. Array form (recommended) — each segment is taken verbatim
|
|
204
|
+
await get<string>(['runtime', 'id']);
|
|
205
|
+
|
|
206
|
+
// 2. Multiple string arguments — each argument is one segment
|
|
207
|
+
await get<string>('runtime', 'id');
|
|
208
|
+
|
|
209
|
+
// 3. Single dotted string — split on `.`
|
|
210
|
+
await get<string>('runtime.id');
|
|
176
211
|
```
|
|
177
212
|
|
|
213
|
+
You can also start from a nested proxy node:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
await chrome.runtime.$get<string>('id');
|
|
217
|
+
await chrome.runtime.$get<string>(['id']);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Symbols are allowed as path keys (must be `Symbol.for(...)` or a well-known symbol so identity survives the wire):
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const queryKey = Symbol.for('queryBySymbol');
|
|
224
|
+
await get(queryKey);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Dotted Keys: Use the Array Form
|
|
228
|
+
|
|
229
|
+
The dotted-string form is convenient, but it **splits on every `.` it finds**, so it cannot address keys that contain a dot — for example `chrome.storage.local`'s users sometimes store entries under names like `'user.email'` or `'flag.v2'`. To address those safely, use the array form (or pass each segment as its own argument):
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
// ❌ Wrong — the dotted form would try to read `local.user.email`
|
|
233
|
+
await get('storage.local.user.email');
|
|
234
|
+
|
|
235
|
+
// ✅ Correct — the array form treats `user.email` as a single key
|
|
236
|
+
await get(['storage', 'local', 'user.email']);
|
|
237
|
+
|
|
238
|
+
// ✅ Also correct — multiple arguments are kept verbatim
|
|
239
|
+
await get('storage', 'local', 'user.email');
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Rule of thumb: **prefer the array form whenever the path is dynamic or comes from data you don't fully control.** Reserve the dotted-string form for short, hand-written, static lookups.
|
|
243
|
+
|
|
178
244
|
## API
|
|
179
245
|
|
|
180
246
|
### `exposeChromeInIframe(options)`
|
|
@@ -188,6 +254,11 @@ const bridge = exposeChromeInIframe({
|
|
|
188
254
|
targetOrigin,
|
|
189
255
|
allowedOrigin,
|
|
190
256
|
chromeApi,
|
|
257
|
+
timeout,
|
|
258
|
+
functionCacheMax,
|
|
259
|
+
functionCacheTtl,
|
|
260
|
+
remoteCallbackCacheMax,
|
|
261
|
+
remoteCallbackCacheTtl,
|
|
191
262
|
});
|
|
192
263
|
```
|
|
193
264
|
|
|
@@ -195,15 +266,18 @@ Options:
|
|
|
195
266
|
|
|
196
267
|
- `iframe`: the iframe element to bridge.
|
|
197
268
|
- `key`: optional shared bridge key. Use the same key on both sides.
|
|
198
|
-
- `targetOrigin`: optional origin used by `postMessage`.
|
|
199
|
-
- `allowedOrigin`: optional origin, origin list, or predicate used to filter incoming messages.
|
|
269
|
+
- `targetOrigin`: optional origin used by `postMessage`. Falls back to a value resolved from `iframe.src`.
|
|
270
|
+
- `allowedOrigin`: optional origin, origin list, or predicate used to filter incoming messages. Defaults to the resolved `targetOrigin` when it is a concrete origin.
|
|
200
271
|
- `chromeApi`: optional custom Chrome-like object. Defaults to `globalThis.chrome`.
|
|
272
|
+
- `timeout`: optional per-call timeout in ms (default `30000`).
|
|
273
|
+
- `functionCacheMax` / `functionCacheTtl`: tune the LRU that stores non-persistent callbacks the local side has sent.
|
|
274
|
+
- `remoteCallbackCacheMax` / `remoteCallbackCacheTtl`: tune the LRU that stores callbacks the remote side has handed to us.
|
|
201
275
|
|
|
202
276
|
Returns:
|
|
203
277
|
|
|
204
278
|
- `proxy`: the bridged Chrome API proxy.
|
|
205
|
-
- `get(path)`: read a property from the bridged Chrome API.
|
|
206
|
-
- `destroy()`: remove message listeners
|
|
279
|
+
- `get(path)`: read a property from the bridged Chrome API. See [Path Forms](#path-forms).
|
|
280
|
+
- `destroy()`: remove message listeners, clear bridge state, and tell the remote peer to release any callbacks it is holding on our behalf.
|
|
207
281
|
|
|
208
282
|
### `connectChromeInIframe(options)`
|
|
209
283
|
|
|
@@ -214,6 +288,11 @@ const { chrome, get, destroy } = connectChromeInIframe({
|
|
|
214
288
|
key,
|
|
215
289
|
targetOrigin,
|
|
216
290
|
allowedOrigin,
|
|
291
|
+
timeout,
|
|
292
|
+
functionCacheMax,
|
|
293
|
+
functionCacheTtl,
|
|
294
|
+
remoteCallbackCacheMax,
|
|
295
|
+
remoteCallbackCacheTtl,
|
|
217
296
|
});
|
|
218
297
|
```
|
|
219
298
|
|
|
@@ -221,6 +300,21 @@ Returns:
|
|
|
221
300
|
|
|
222
301
|
- `chrome`: a proxy for the extension page's Chrome API.
|
|
223
302
|
- `proxy`: the same object as `chrome`.
|
|
224
|
-
- `get(path)`: read a property from the bridged Chrome API.
|
|
225
|
-
- `destroy()`: remove message listeners
|
|
303
|
+
- `get(path)`: read a property from the bridged Chrome API. See [Path Forms](#path-forms).
|
|
304
|
+
- `destroy()`: remove message listeners, clear bridge state, and notify the remote peer.
|
|
305
|
+
|
|
306
|
+
### `setLogger(logger)`
|
|
307
|
+
|
|
308
|
+
Customize or silence library warnings. All internal warnings carry a `[chrome-in-iframe]` prefix and a scope tag.
|
|
226
309
|
|
|
310
|
+
```ts
|
|
311
|
+
import { setLogger } from 'chrome-in-iframe';
|
|
312
|
+
|
|
313
|
+
// Silence all warnings
|
|
314
|
+
setLogger(null);
|
|
315
|
+
|
|
316
|
+
// Route warnings to a custom sink (e.g. Sentry)
|
|
317
|
+
setLogger((scope, ...args) => {
|
|
318
|
+
captureMessage(`[chrome-in-iframe] ${scope}`, { extra: { args } });
|
|
319
|
+
});
|
|
320
|
+
```
|
package/README.zh-CN.md
CHANGED
|
@@ -8,6 +8,20 @@
|
|
|
8
8
|
|
|
9
9
|
当扩展页面(如 `options.html`、`popup.html` 或其他 `chrome-extension://...` 页面)嵌入了 iframe,但 iframe 本身无法直接访问 Chrome 扩展 API 时,这个库非常有用。
|
|
10
10
|
|
|
11
|
+
## 模块格式
|
|
12
|
+
|
|
13
|
+
**本包只提供 ESM。** 发布产物是单个 ECMAScript 模块,没有 CommonJS 入口。请在 ESM 项目中使用(Vite、Rollup、webpack 5+、Parcel 2+、其他现代打包器,或浏览器原生 `<script type="module">`)。
|
|
14
|
+
|
|
15
|
+
`require('chrome-in-iframe')` 无法工作。
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"type": "module"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
如果你的构建工具仍然产出 CommonJS,请将 `chrome-in-iframe` 配置为 ESM external,或将消费方项目迁移到 ESM。
|
|
24
|
+
|
|
11
25
|
## 安装
|
|
12
26
|
|
|
13
27
|
```bash
|
|
@@ -133,11 +147,11 @@ window.addEventListener('beforeunload', () => {
|
|
|
133
147
|
|
|
134
148
|
## 安全选项
|
|
135
149
|
|
|
136
|
-
`targetOrigin` 和 `allowedOrigin`
|
|
150
|
+
`targetOrigin` 和 `allowedOrigin` 是可选的。当不传 `targetOrigin` 时,库会自动从 `iframe.src` / `contentWindow.location.origin`(扩展侧)或 `document.referrer` / `location.ancestorOrigins`(iframe 侧)推导出 origin;只有在以上来源都不可用时才回退到 `'*'`。传入的消息默认同时校验预期的 window source,以及为 `targetOrigin` 推导出的同一个 origin。
|
|
137
151
|
|
|
138
|
-
>
|
|
152
|
+
> **警告**:如果自动推导无法得到具体 origin 并回退到 `'*'`,来自预期 window source 的传入消息会允许任意 origin。对于第三方 iframe、可能被导航的 iframe,或任何不同 origin 的页面,请显式传入 `targetOrigin` 和 `allowedOrigin`。
|
|
139
153
|
|
|
140
|
-
|
|
154
|
+
在生产环境中,如果知道具体来源,建议显式传入 origin。
|
|
141
155
|
|
|
142
156
|
### 扩展页面
|
|
143
157
|
|
|
@@ -160,6 +174,17 @@ const { chrome } = connectChromeInIframe({
|
|
|
160
174
|
});
|
|
161
175
|
```
|
|
162
176
|
|
|
177
|
+
## 跨桥的数据类型
|
|
178
|
+
|
|
179
|
+
桥接层支持 `undefined`、`null`、所有原始类型(含 `bigint`、`NaN`、`Infinity`、`-0`)、普通对象(字符串键和 symbol 键都行)、数组、函数、`Error`(保留 `name`、`stack`、`cause`)、`Date`、`RegExp`、`Map`、`Set`。循环引用会抛错。
|
|
180
|
+
|
|
181
|
+
任何 RPC 桥接都有的固有限制:
|
|
182
|
+
|
|
183
|
+
- **对象身份不被保留。** 跨桥的 `Date`、`Map`、`Set`、普通对象会在对端被重新构造。原对象和往返后的对象之间 `===` 为 `false`。
|
|
184
|
+
- **以对象为 key 的 Map / Set 会丢失查找能力。** 把 `Date`(或任何对象)作为 `Map` 的 key,跨桥之后,对端 `map.get(originalDate)` 找不到 —— 反序列化得到的 `Map` 里持有的是另一个 `Date` 实例。需要跨桥传输的 `Map`,请用字符串或数字作 key。
|
|
185
|
+
- **非全局 symbol 不能跨桥。** 用 `Symbol.for(...)` 或 well-known symbol;临时 `Symbol('local')` 在序列化时抛错。
|
|
186
|
+
- **类原型会被擦除。** `class Foo { ... }` 的实例到对端只是一个普通对象,只保留可枚举字段;`instanceof Foo` 为 `false`。
|
|
187
|
+
|
|
163
188
|
## 读取属性
|
|
164
189
|
|
|
165
190
|
Chrome API 方法可以直接调用:
|
|
@@ -168,13 +193,54 @@ Chrome API 方法可以直接调用:
|
|
|
168
193
|
const tabs = await chrome.tabs.query({ active: true });
|
|
169
194
|
```
|
|
170
195
|
|
|
171
|
-
|
|
196
|
+
非函数的可读属性应通过 `get()`(由 `connectChromeInIframe` 返回)或代理上任意节点的 `$get()` 读取。
|
|
197
|
+
|
|
198
|
+
### 路径形式
|
|
199
|
+
|
|
200
|
+
`$get` / `get` 支持三种等价的路径写法:
|
|
172
201
|
|
|
173
202
|
```ts
|
|
174
|
-
|
|
175
|
-
|
|
203
|
+
// 1. 数组形式(推荐)—— 每个元素都被视为单独一段
|
|
204
|
+
await get<string>(['runtime', 'id']);
|
|
205
|
+
|
|
206
|
+
// 2. 多参数字符串 —— 每个参数都是单独一段
|
|
207
|
+
await get<string>('runtime', 'id');
|
|
208
|
+
|
|
209
|
+
// 3. 单个带 `.` 的字符串 —— 按 `.` 自动拆分
|
|
210
|
+
await get<string>('runtime.id');
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
也可以从代理的中间节点开始:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
await chrome.runtime.$get<string>('id');
|
|
217
|
+
await chrome.runtime.$get<string>(['id']);
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Symbol 也可以作为路径片段(必须是 `Symbol.for(...)` 或 well-known symbol,以便在序列化后仍能保持身份):
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const queryKey = Symbol.for('queryBySymbol');
|
|
224
|
+
await get(queryKey);
|
|
176
225
|
```
|
|
177
226
|
|
|
227
|
+
### 含 `.` 的键:请用数组形式
|
|
228
|
+
|
|
229
|
+
字符串带 `.` 的写法很方便,但会**对每一个 `.` 都做拆分**,所以无法访问 key 本身就包含 `.` 的属性 —— 例如 `chrome.storage.local` 的使用者经常会存 `'user.email'`、`'flag.v2'` 这类条目。要安全访问它们,必须改用数组形式(或把每段当作独立参数传):
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
// ❌ 错误 —— 字符串形式会把它当作 `local → user → email` 三段
|
|
233
|
+
await get('storage.local.user.email');
|
|
234
|
+
|
|
235
|
+
// ✅ 正确 —— 数组形式把 `user.email` 当作一段
|
|
236
|
+
await get(['storage', 'local', 'user.email']);
|
|
237
|
+
|
|
238
|
+
// ✅ 也正确 —— 多参数形式同样保留原样
|
|
239
|
+
await get('storage', 'local', 'user.email');
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
经验法则:**路径只要是动态的,或者来自不完全可控的数据源,就用数组形式。** 字符串带 `.` 的形式留给短小、手写、静态的查询。
|
|
243
|
+
|
|
178
244
|
## API
|
|
179
245
|
|
|
180
246
|
### `exposeChromeInIframe(options)`
|
|
@@ -188,22 +254,30 @@ const bridge = exposeChromeInIframe({
|
|
|
188
254
|
targetOrigin,
|
|
189
255
|
allowedOrigin,
|
|
190
256
|
chromeApi,
|
|
257
|
+
timeout,
|
|
258
|
+
functionCacheMax,
|
|
259
|
+
functionCacheTtl,
|
|
260
|
+
remoteCallbackCacheMax,
|
|
261
|
+
remoteCallbackCacheTtl,
|
|
191
262
|
});
|
|
192
263
|
```
|
|
193
264
|
|
|
194
265
|
选项:
|
|
195
266
|
|
|
196
267
|
- `iframe`:要桥接的 iframe 元素。
|
|
197
|
-
- `key
|
|
198
|
-
- `targetOrigin`:可选,`postMessage` 使用的 origin
|
|
199
|
-
- `allowedOrigin
|
|
268
|
+
- `key`:可选的共享桥接 key。两侧使用相同的 key。
|
|
269
|
+
- `targetOrigin`:可选,`postMessage` 使用的 origin。不传时由 `iframe.src` 推导。
|
|
270
|
+
- `allowedOrigin`:可选,用于过滤传入消息;可以是 origin、origin 列表或判断函数。默认使用解析后的 `targetOrigin`(当它是具体 origin 时)。
|
|
200
271
|
- `chromeApi`:可选,自定义的 Chrome API 对象。默认为 `globalThis.chrome`。
|
|
272
|
+
- `timeout`:可选,单次调用的超时时长(毫秒,默认 `30000`)。
|
|
273
|
+
- `functionCacheMax` / `functionCacheTtl`:调整本端发出的非持久 callback 的 LRU 缓存。
|
|
274
|
+
- `remoteCallbackCacheMax` / `remoteCallbackCacheTtl`:调整对端发给本端的 callback 的 LRU 缓存。
|
|
201
275
|
|
|
202
276
|
返回值:
|
|
203
277
|
|
|
204
278
|
- `proxy`:桥接后的 Chrome API 代理。
|
|
205
|
-
- `get(path)`:从桥接的 Chrome API
|
|
206
|
-
- `destroy()
|
|
279
|
+
- `get(path)`:从桥接的 Chrome API 中读取属性。详见 [路径形式](#路径形式)。
|
|
280
|
+
- `destroy()`:移除消息监听器,清理桥接状态,并通知对端释放它为我们持有的 callback。
|
|
207
281
|
|
|
208
282
|
### `connectChromeInIframe(options)`
|
|
209
283
|
|
|
@@ -214,6 +288,11 @@ const { chrome, get, destroy } = connectChromeInIframe({
|
|
|
214
288
|
key,
|
|
215
289
|
targetOrigin,
|
|
216
290
|
allowedOrigin,
|
|
291
|
+
timeout,
|
|
292
|
+
functionCacheMax,
|
|
293
|
+
functionCacheTtl,
|
|
294
|
+
remoteCallbackCacheMax,
|
|
295
|
+
remoteCallbackCacheTtl,
|
|
217
296
|
});
|
|
218
297
|
```
|
|
219
298
|
|
|
@@ -221,5 +300,21 @@ const { chrome, get, destroy } = connectChromeInIframe({
|
|
|
221
300
|
|
|
222
301
|
- `chrome`:扩展页面 Chrome API 的代理。
|
|
223
302
|
- `proxy`:与 `chrome` 相同的对象。
|
|
224
|
-
- `get(path)`:从桥接的 Chrome API
|
|
225
|
-
- `destroy()
|
|
303
|
+
- `get(path)`:从桥接的 Chrome API 中读取属性。详见 [路径形式](#路径形式)。
|
|
304
|
+
- `destroy()`:移除消息监听器,清理桥接状态,并通知对端。
|
|
305
|
+
|
|
306
|
+
### `setLogger(logger)`
|
|
307
|
+
|
|
308
|
+
自定义或静默库内警告。所有内部警告均带有 `[chrome-in-iframe]` 前缀和 scope 标签。
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
import { setLogger } from 'chrome-in-iframe';
|
|
312
|
+
|
|
313
|
+
// 静默所有警告
|
|
314
|
+
setLogger(null);
|
|
315
|
+
|
|
316
|
+
// 将警告路由到自定义 sink(如 Sentry)
|
|
317
|
+
setLogger((scope, ...args) => {
|
|
318
|
+
captureMessage(`[chrome-in-iframe] ${scope}`, { extra: { args } });
|
|
319
|
+
});
|
|
320
|
+
```
|
package/dist/api.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ export interface ConnectionOptions {
|
|
|
11
11
|
timeout?: number;
|
|
12
12
|
targetOrigin?: string;
|
|
13
13
|
allowedOrigin?: AllowedOrigin;
|
|
14
|
+
functionCacheMax?: number;
|
|
15
|
+
functionCacheTtl?: number;
|
|
16
|
+
remoteCallbackCacheMax?: number;
|
|
17
|
+
remoteCallbackCacheTtl?: number;
|
|
14
18
|
}
|
|
15
19
|
export interface SetupInMainWindowOptions<T = unknown> extends ConnectionOptions {
|
|
16
20
|
iframe: HTMLIFrameElement;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ProcessorRegistry } from '../processor/registry';
|
|
2
2
|
import type { ClientContext, MessageChannel, MessagePoster } from './types';
|
|
3
|
-
export declare function createMessageChannel(poster: MessagePoster, key: string, context: ClientContext, processorRegistry: ProcessorRegistry): MessageChannel;
|
|
3
|
+
export declare function createMessageChannel(poster: MessagePoster, key: string, instanceId: string, context: ClientContext, processorRegistry: ProcessorRegistry): MessageChannel;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import type { Callable, CallbackCacheOptions, MessageValue } from './types';
|
|
2
|
-
export
|
|
2
|
+
export type GenerateCallbackFn = (id: string, args: MessageValue[], options?: CallbackCacheOptions) => MessageValue;
|
|
3
|
+
export type GetRemoteCallbackFn = (id: string, invoke: (args: MessageValue[]) => MessageValue, options?: CallbackCacheOptions) => Callable;
|
|
4
|
+
export declare function deserialize(arg: MessageValue, generateCallback: GenerateCallbackFn, getRemoteCallback?: GetRemoteCallbackFn): MessageValue;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PathKey } from './types';
|
|
2
2
|
export declare function isListenerRegistrationPath(path: PathKey[]): boolean;
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function isListenerRemovalPath(path: PathKey[]): boolean;
|
|
4
|
+
export declare function isLikelyListenerPath(path: PathKey[]): boolean;
|
package/dist/channel/sender.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { MessagePoster, MessageSender } from './types';
|
|
2
|
-
export declare function createMessageSender(poster: MessagePoster, key: string): MessageSender;
|
|
2
|
+
export declare function createMessageSender(poster: MessagePoster, key: string, instanceId: string): MessageSender;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import type { Callable, CallbackCacheOptions, MessageValue } from './types';
|
|
2
|
-
export declare
|
|
2
|
+
export declare const TYPE_KEY = "$cii$";
|
|
3
|
+
export type RegisterFunctionFn = (fn: Callable, thisArg: MessageValue, options?: CallbackCacheOptions) => string;
|
|
4
|
+
export declare function serialize(arg: MessageValue, registerFunction: RegisterFunctionFn, options?: CallbackCacheOptions): MessageValue;
|
package/dist/channel/types.d.ts
CHANGED
|
@@ -40,12 +40,20 @@ export interface Messages {
|
|
|
40
40
|
data?: MessageValue;
|
|
41
41
|
error?: SerializedError;
|
|
42
42
|
};
|
|
43
|
+
releaseCallbacks: {
|
|
44
|
+
ids: string[];
|
|
45
|
+
};
|
|
46
|
+
destroyEndpoint: {
|
|
47
|
+
instanceId: string;
|
|
48
|
+
};
|
|
43
49
|
}
|
|
44
50
|
export type MessageType = keyof Messages;
|
|
45
51
|
export type MessageBody<K extends MessageType = MessageType> = {
|
|
46
52
|
type: K;
|
|
47
53
|
key: string;
|
|
48
54
|
data: Messages[K];
|
|
55
|
+
senderInstanceId: string;
|
|
56
|
+
targetInstanceId?: string;
|
|
49
57
|
};
|
|
50
58
|
export interface MessagePoster {
|
|
51
59
|
postMessage(message: string): void;
|
|
@@ -56,36 +64,51 @@ export interface PromiseCallbacks {
|
|
|
56
64
|
resolve: (value: MessageValue) => void;
|
|
57
65
|
reject: (reason: MessageValue) => void;
|
|
58
66
|
timer: ReturnType<typeof setTimeout>;
|
|
67
|
+
onResolve?: () => void;
|
|
68
|
+
onReject?: () => void;
|
|
59
69
|
}
|
|
60
70
|
export interface ClientContext {
|
|
61
71
|
getDelegateTarget(): MessageValue;
|
|
62
72
|
getMessageChannel(): MessageChannel;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
getInstanceId(): string;
|
|
74
|
+
getFunctionCache(): LRUCache<string, CallbackEntry>;
|
|
75
|
+
getPersistentFunctionCache(): Map<string, CallbackEntry>;
|
|
76
|
+
registerFunction(fn: Callable, thisArg: MessageValue, options?: CallbackCacheOptions): string;
|
|
77
|
+
getRemoteCallback(id: string, invoke: (args: MessageValue[]) => MessageValue, options: CallbackCacheOptions | undefined, remoteInstanceId: string): Callable;
|
|
67
78
|
getAndRemovePendingPromise(id: RequestId): PromiseCallbacks | undefined;
|
|
68
79
|
invoke(path: PathKey[], args: MessageValue[]): Promise<MessageValue>;
|
|
69
80
|
accessProperty(path: PathKey[]): Promise<MessageValue>;
|
|
70
81
|
invokeFunctionById(id: string, args: MessageValue[], options?: CallbackCacheOptions): Promise<MessageValue>;
|
|
71
|
-
|
|
72
|
-
|
|
82
|
+
handleRemoteDestroy(instanceId: string): void;
|
|
83
|
+
releaseRemoteCallbacks(remoteInstanceId: string, ids: readonly string[]): void;
|
|
84
|
+
dropLocalCallback(id: string): void;
|
|
85
|
+
bindMethod(fn: Callable, owner: MessageValue): Callable;
|
|
86
|
+
/** @internal Exposed for tests; do not use in application code. */
|
|
87
|
+
getRemoteCallbackCounts(remoteInstanceId: string): {
|
|
88
|
+
lru: number;
|
|
89
|
+
persistent: number;
|
|
90
|
+
};
|
|
91
|
+
destroy(notifyRemote?: boolean): void;
|
|
73
92
|
}
|
|
74
93
|
export interface CallbackCacheOptions {
|
|
75
94
|
persistent?: boolean;
|
|
76
95
|
}
|
|
96
|
+
export interface CallbackEntry {
|
|
97
|
+
fn: Callable;
|
|
98
|
+
thisArg: MessageValue;
|
|
99
|
+
}
|
|
77
100
|
export interface MessageChannel {
|
|
78
101
|
getSender(): MessageSender;
|
|
79
|
-
getContext(): ClientContext;
|
|
80
|
-
getPoster(): MessagePoster;
|
|
81
|
-
getKey(): string;
|
|
82
102
|
destroy(): void;
|
|
83
103
|
}
|
|
84
104
|
export interface MessageSender {
|
|
85
|
-
sendMessage<K extends MessageType>(type: K, data: Messages[K]): void;
|
|
105
|
+
sendMessage<K extends MessageType>(type: K, data: Messages[K], targetInstanceId?: string): void;
|
|
86
106
|
}
|
|
87
107
|
export interface RequestHandler<K extends MessageType = MessageType> {
|
|
88
|
-
(data: Messages[K], ctx: ClientContext): void;
|
|
108
|
+
(data: Messages[K], ctx: ClientContext, meta: MessageMeta): void;
|
|
109
|
+
}
|
|
110
|
+
export interface MessageMeta {
|
|
111
|
+
senderInstanceId: string;
|
|
89
112
|
}
|
|
90
113
|
export type ProxyNode = {
|
|
91
114
|
parent?: ProxyNode;
|
package/dist/channel/utils.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export declare const WELL_KNOWN_SYMBOLS: Record<string, symbol>;
|
|
|
3
3
|
export declare function getWellKnownSymbolName(value: symbol): string | undefined;
|
|
4
4
|
export declare function getWellKnownSymbol(name: string): symbol | undefined;
|
|
5
5
|
export declare function serializeThrownError(err: unknown): SerializedError;
|
|
6
|
+
export declare function isPromiseLike(value: unknown): value is PromiseLike<unknown>;
|
package/dist/client/context.d.ts
CHANGED
|
@@ -2,5 +2,9 @@ import type { ClientContext, MessageChannel, MessageValue } from '../channel/typ
|
|
|
2
2
|
export interface ClientContextOptions {
|
|
3
3
|
delegateTarget?: MessageValue;
|
|
4
4
|
timeout?: number;
|
|
5
|
+
functionCacheMax?: number;
|
|
6
|
+
functionCacheTtl?: number;
|
|
7
|
+
remoteCallbackCacheMax?: number;
|
|
8
|
+
remoteCallbackCacheTtl?: number;
|
|
5
9
|
}
|
|
6
|
-
export declare function createClientContext(getMessageChannel: () => MessageChannel, options?: ClientContextOptions): ClientContext;
|
|
10
|
+
export declare function createClientContext(getMessageChannel: () => MessageChannel, instanceId: string, options?: ClientContextOptions): ClientContext;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MessagePoster } from '../channel/types';
|
|
1
|
+
import type { ClientContext, MessagePoster } from '../channel/types';
|
|
2
2
|
import { type ClientContextOptions } from './context';
|
|
3
3
|
export interface EndpointOptions {
|
|
4
4
|
poster: MessagePoster;
|
|
@@ -8,5 +8,7 @@ export interface EndpointOptions {
|
|
|
8
8
|
export interface Endpoint<TProxy = unknown> {
|
|
9
9
|
proxy: TProxy;
|
|
10
10
|
destroy: () => void;
|
|
11
|
+
/** @internal Exposed for tests; do not use in application code. */
|
|
12
|
+
getContext: () => ClientContext;
|
|
11
13
|
}
|
|
12
14
|
export declare function createEndpoint<TProxy = unknown>(options: EndpointOptions): Endpoint<TProxy>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { connectChromeInIframe, exposeChromeInIframe, setupInIframe, setupInMainWindow } from './api';
|
|
2
|
+
export { setLogger } from './log';
|
|
3
|
+
export type { Logger } from './log';
|
|
2
4
|
export type { AllowedOrigin, PropertyAccess, PropertyPathPart, ConnectionHandle, ChromeIframeHandle, ExposeChromeInIframeOptions, SetupInIframeOptions, SetupInMainWindowOptions, ConnectionOptions, } from './api';
|
|
3
5
|
export type { Messages, MessageType, MessageBody, MessagePoster, ClientContext, MessageChannel, MessageSender, ProxyNode, ListenerCallback, SerializedError, } from './channel/types';
|