iframe-bridge-kit 1.0.1 → 1.1.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/LICENSE +20 -20
- package/README.md +218 -181
- package/dist/full/core.js +1 -1
- package/dist/full/core.mjs +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +157 -18
- package/dist/index.mjs +157 -18
- package/dist/mini/core.js +1 -1
- package/dist/mini/core.mjs +1 -1
- package/dist/vite.js +37 -18
- package/dist/vite.mjs +37 -18
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 ZhangSan<2306860505@qq.com>
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ZhangSan<2306860505@qq.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,182 +1,219 @@
|
|
|
1
|
-
# iframe-bridge-kit
|
|
2
|
-
|
|
3
|
-
[English](./README.md) | [简体中文](https://github.com/mchao123/iframe-bridge-kit/blob/master/README_zh.md)
|
|
4
|
-
|
|
5
|
-
`iframe-bridge-kit` is an iframe communication library based on [Vite](https://vitejs.dev/) and [Penpal](https://www.google.com/search?q=https://github.com/google/penpal). It uses a Vite plugin to automatically generate type definitions, allowing you to call parent window methods from the iframe (child window) with **100% TypeScript type hints**, just like calling local functions.
|
|
6
|
-
|
|
7
|
-
## ✨ Features
|
|
8
|
-
|
|
9
|
-
* 🔒 **Type Safe**: Automatically generates `.d.ts` based on source code; parent and child windows share identical types.
|
|
10
|
-
* 🚀 **Zero Runtime Definition**: No need to manually define interfaces in the child window; simply import the generated bridge file to use.
|
|
11
|
-
* 📡 **RPC Style**: Call cross-window methods just like calling `async` functions.
|
|
12
|
-
* ⚡ **Event Mechanism**: Supports sending strongly-typed broadcast messages from the parent window to the child window.
|
|
13
|
-
* 🛠 **Vite Integration**: Designed specifically for the Vite ecosystem with HMR support.
|
|
14
|
-
|
|
15
|
-
## 📦 Installation
|
|
16
|
-
|
|
17
|
-
You need to install both `iframe-bridge-kit` and its peer dependency `penpal`.
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install iframe-bridge-kit penpal
|
|
21
|
-
# or
|
|
22
|
-
pnpm add iframe-bridge-kit penpal
|
|
23
|
-
# or
|
|
24
|
-
yarn add iframe-bridge-kit penpal
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## ⚙️ Configuration
|
|
28
|
-
|
|
29
|
-
Import the plugin in your `vite.config.ts`.
|
|
30
|
-
|
|
31
|
-
```typescript
|
|
32
|
-
// vite.config.ts
|
|
33
|
-
import { defineConfig } from 'vite'
|
|
34
|
-
import vue from '@vitejs/plugin-vue' // or other framework plugins
|
|
35
|
-
import vitePluginIframeBridge from 'iframe-bridge-kit/vite'
|
|
36
|
-
|
|
37
|
-
export default defineConfig({
|
|
38
|
-
plugins: [
|
|
39
|
-
vue(),
|
|
40
|
-
vitePluginIframeBridge({
|
|
41
|
-
// Output directory, default is 'src/bridges' (recommended to place under src for easy import)
|
|
42
|
-
outDir: 'src/bridges',
|
|
43
|
-
// Whether to generate full code (including Penpal dependency), default is true
|
|
44
|
-
full: true
|
|
45
|
-
})
|
|
46
|
-
]
|
|
47
|
-
})
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## 📖 Usage Guide
|
|
51
|
-
|
|
52
|
-
### 1\. Parent Window (Host/Parent)
|
|
53
|
-
|
|
54
|
-
In the parent window, use `defineBridge` to define the methods and event types exposed to the iframe.
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
// src/views/Parent.vue (or other .ts files)
|
|
58
|
-
import { defineBridge } from 'iframe-bridge-kit'
|
|
59
|
-
import { ref, onMounted } from 'vue'
|
|
60
|
-
|
|
61
|
-
// Define event types sent from Parent to Child
|
|
62
|
-
interface EmitMap {
|
|
63
|
-
'theme-change': { mode: 'dark' | 'light' }
|
|
64
|
-
'user-logout': void
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// 1. Define Bridge
|
|
68
|
-
// The first argument 'app-bridge' is the bridge name, used for folder generation
|
|
69
|
-
export const mainBridge = defineBridge<EmitMap>('app-bridge', {
|
|
70
|
-
// Methods exposed to the iframe
|
|
71
|
-
async getUserInfo(id: string) {
|
|
72
|
-
return { id, name: 'John Doe', role: 'admin' }
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
updateTitle(title: string) {
|
|
76
|
-
document.title = title
|
|
77
|
-
return true
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
// 2. Bind iframe
|
|
82
|
-
const iframeRef = ref<HTMLIFrameElement>()
|
|
83
|
-
|
|
84
|
-
onMounted(async () => {
|
|
85
|
-
if (iframeRef.value) {
|
|
86
|
-
const child = await mainBridge.create(iframeRef.value)
|
|
87
|
-
|
|
88
|
-
// Send message to iframe
|
|
89
|
-
child.emit('theme-change', { mode: 'dark' })
|
|
90
|
-
}
|
|
91
|
-
})
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
> **Note**: After saving the file, the Vite plugin will automatically scan for `defineBridge` and generate the corresponding type definitions and runtime code under `src/bridges/app-bridge/`.
|
|
95
|
-
|
|
96
|
-
### 2\. Child Window (Iframe/Child)
|
|
97
|
-
|
|
98
|
-
In the iframe project, **directly import the file generated by the plugin**. All API methods have strict type inference.
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
// src/views/IframeChild.vue
|
|
102
|
-
// Import from the generated directory (path depends on your outDir config)
|
|
103
|
-
import
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
1
|
+
# iframe-bridge-kit
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | [简体中文](https://github.com/mchao123/iframe-bridge-kit/blob/master/README_zh.md)
|
|
4
|
+
|
|
5
|
+
`iframe-bridge-kit` is an iframe communication library based on [Vite](https://vitejs.dev/) and [Penpal](https://www.google.com/search?q=https://github.com/google/penpal). It uses a Vite plugin to automatically generate type definitions, allowing you to call parent window methods from the iframe (child window) with **100% TypeScript type hints**, just like calling local functions.
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
* 🔒 **Type Safe**: Automatically generates `.d.ts` based on source code; parent and child windows share identical types.
|
|
10
|
+
* 🚀 **Zero Runtime Definition**: No need to manually define interfaces in the child window; simply import the generated bridge file to use.
|
|
11
|
+
* 📡 **RPC Style**: Call cross-window methods just like calling `async` functions.
|
|
12
|
+
* ⚡ **Event Mechanism**: Supports sending strongly-typed broadcast messages from the parent window to the child window.
|
|
13
|
+
* 🛠 **Vite Integration**: Designed specifically for the Vite ecosystem with HMR support.
|
|
14
|
+
|
|
15
|
+
## 📦 Installation
|
|
16
|
+
|
|
17
|
+
You need to install both `iframe-bridge-kit` and its peer dependency `penpal`.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install iframe-bridge-kit penpal
|
|
21
|
+
# or
|
|
22
|
+
pnpm add iframe-bridge-kit penpal
|
|
23
|
+
# or
|
|
24
|
+
yarn add iframe-bridge-kit penpal
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## ⚙️ Configuration
|
|
28
|
+
|
|
29
|
+
Import the plugin in your `vite.config.ts`.
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// vite.config.ts
|
|
33
|
+
import { defineConfig } from 'vite'
|
|
34
|
+
import vue from '@vitejs/plugin-vue' // or other framework plugins
|
|
35
|
+
import vitePluginIframeBridge from 'iframe-bridge-kit/vite'
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
plugins: [
|
|
39
|
+
vue(),
|
|
40
|
+
vitePluginIframeBridge({
|
|
41
|
+
// Output directory, default is 'src/bridges' (recommended to place under src for easy import)
|
|
42
|
+
outDir: 'src/bridges',
|
|
43
|
+
// Whether to generate full code (including Penpal dependency), default is true
|
|
44
|
+
full: true
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 📖 Usage Guide
|
|
51
|
+
|
|
52
|
+
### 1\. Parent Window (Host/Parent)
|
|
53
|
+
|
|
54
|
+
In the parent window, use `defineBridge` to define the methods and event types exposed to the iframe.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// src/views/Parent.vue (or other .ts files)
|
|
58
|
+
import { defineBridge } from 'iframe-bridge-kit'
|
|
59
|
+
import { ref, onMounted } from 'vue'
|
|
60
|
+
|
|
61
|
+
// Define event types sent from Parent to Child
|
|
62
|
+
interface EmitMap {
|
|
63
|
+
'theme-change': { mode: 'dark' | 'light' }
|
|
64
|
+
'user-logout': void
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 1. Define Bridge
|
|
68
|
+
// The first argument 'app-bridge' is the bridge name, used for folder generation
|
|
69
|
+
export const mainBridge = defineBridge<EmitMap>('app-bridge', {
|
|
70
|
+
// Methods exposed to the iframe
|
|
71
|
+
async getUserInfo(id: string) {
|
|
72
|
+
return { id, name: 'John Doe', role: 'admin' }
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
updateTitle(title: string) {
|
|
76
|
+
document.title = title
|
|
77
|
+
return true
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// 2. Bind iframe
|
|
82
|
+
const iframeRef = ref<HTMLIFrameElement>()
|
|
83
|
+
|
|
84
|
+
onMounted(async () => {
|
|
85
|
+
if (iframeRef.value) {
|
|
86
|
+
const child = await mainBridge.create(iframeRef.value)
|
|
87
|
+
|
|
88
|
+
// Send message to iframe
|
|
89
|
+
child.emit('theme-change', { mode: 'dark' })
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> **Note**: After saving the file, the Vite plugin will automatically scan for `defineBridge` and generate the corresponding type definitions and runtime code under `src/bridges/app-bridge/`.
|
|
95
|
+
|
|
96
|
+
### 2\. Child Window (Iframe/Child)
|
|
97
|
+
|
|
98
|
+
In the iframe project, **directly import the file generated by the plugin**. All API methods have strict type inference.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// src/views/IframeChild.vue
|
|
102
|
+
// Import from the generated directory (path depends on your outDir config)
|
|
103
|
+
import createParentBridge from '../bridges/app-bridge'
|
|
104
|
+
|
|
105
|
+
const parent = createParentBridge()
|
|
106
|
+
|
|
107
|
+
// Wait for connection initialization (optional)
|
|
108
|
+
parent.onInit(() => {
|
|
109
|
+
console.log('Bridge connected!')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// 1. Call parent window methods (RPC)
|
|
113
|
+
async function fetchUser() {
|
|
114
|
+
// ✅ Full type hints for id and return value here!
|
|
115
|
+
const user = await parent.getUserInfo('123')
|
|
116
|
+
console.log(user.name)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 2. Listen for parent window messages
|
|
120
|
+
// ✅ Type hints for 'theme-change' and callback data
|
|
121
|
+
parent.onMessage('theme-change', (data) => {
|
|
122
|
+
console.log('New theme:', data.mode)
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 3\. Reverse Calls: Child Defines API, Parent Calls It
|
|
127
|
+
|
|
128
|
+
If the API is defined inside the iframe, the parent can import the same generated file and explicitly pass the target `Window` to establish the connection. Each default factory call returns an independent instance, so it works cleanly with multiple iframes.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// inside iframe
|
|
132
|
+
import { defineBridge } from 'iframe-bridge-kit'
|
|
133
|
+
|
|
134
|
+
export const childBridge = defineBridge('child-api', {
|
|
135
|
+
async getSelection() {
|
|
136
|
+
return window.getSelection()?.toString() || ''
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
childBridge.create(window.parent)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// parent window
|
|
145
|
+
import { createBridgeClient } from '../bridges/child-api'
|
|
146
|
+
|
|
147
|
+
const iframeEl = document.querySelector('iframe')!
|
|
148
|
+
|
|
149
|
+
if (!iframeEl.contentWindow) {
|
|
150
|
+
throw new Error('iframe is not ready')
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const child = createBridgeClient(iframeEl.contentWindow)
|
|
154
|
+
const text = await child.getSelection()
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The default child-window flow can call the default function, which reuses a singleton client connected to `window.parent`. When the parent wants to call APIs defined by the iframe, create an independent instance with `createBridgeClient(iframe.contentWindow)`.
|
|
158
|
+
|
|
159
|
+
## 🧩 Type Support Details
|
|
160
|
+
|
|
161
|
+
The core magic of `iframe-bridge-kit` lies in how it handles types.
|
|
162
|
+
|
|
163
|
+
When you define methods:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
getUserInfo(id: string): Promise<User>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The plugin extracts the `User` interface (even types imported from `node_modules`) and **copies** it into the generated `index.d.ts`. This means the child window does not need access to the parent's source code or dependencies to get perfect type hints.
|
|
170
|
+
|
|
171
|
+
### Supported Type Features
|
|
172
|
+
|
|
173
|
+
* Basic types (string, number, boolean)
|
|
174
|
+
* Interfaces & Type Aliases
|
|
175
|
+
* Generic Expansion
|
|
176
|
+
* Third-party library types (automatically handles import paths)
|
|
177
|
+
|
|
178
|
+
## 🔌 API Reference
|
|
179
|
+
|
|
180
|
+
### `defineBridge<TEmit>(name, methods)`
|
|
181
|
+
|
|
182
|
+
* **name**: `string` - Bridge name, determines the generated directory name.
|
|
183
|
+
* **methods**: `Object` - Collection of methods exposed to the child window.
|
|
184
|
+
* **TEmit**: `Generic` - (Optional) Defines the event type mapping for messages sent via `emit` from the parent.
|
|
185
|
+
|
|
186
|
+
Returns an object containing:
|
|
187
|
+
|
|
188
|
+
* `create(target, allowedOrigins?)`: Initializes the connection. `target` may be an `HTMLIFrameElement` or `Window`, and the return value is an `{ emit, destroy }` object.
|
|
189
|
+
|
|
190
|
+
### Vite Plugin Options (`IframeBridgeOptions`)
|
|
191
|
+
|
|
192
|
+
| Option | Type | Default | Description |
|
|
193
|
+
|:---|:---|:---|:---|
|
|
194
|
+
| `outDir` | `string` | `'bridges'` | Output directory for generated code. Recommended `'src/bridges'`. |
|
|
195
|
+
| `allowedOrigins` | `string[]` | `['*']` | List of allowed origin domains for communication. |
|
|
196
|
+
| `full` | `boolean` | `true` | Whether to generate code containing full dependencies. |
|
|
197
|
+
| `preserveModules` | `string[]` | `[]` | Preserve imports for specific modules instead of expanding types (e.g., `['vue']`). |
|
|
198
|
+
|
|
199
|
+
### Generated Runtime API
|
|
200
|
+
|
|
201
|
+
Assuming `outDir` is `src/bridges` and the bridge name is `my-bridge`, you can import from `src/bridges/my-bridge`:
|
|
202
|
+
|
|
203
|
+
* **`default` (createBridge)**: Returns the default singleton `BridgeClient` connected to `window.parent`, suitable for child-to-parent calls.
|
|
204
|
+
* **`createBridgeClient(remoteWindow, allowedOrigins?)`**: Named multi-instance factory export. It requires an explicit `Window` and is suitable when the parent manages one or more iframes.
|
|
205
|
+
* **`client.onMessage(type, callback, once?)`**: Listen for events sent by the remote bridge.
|
|
206
|
+
* **`client.offMessage(type, callback?)`**: Remove an event listener.
|
|
207
|
+
* **`client.onInit(callback)`**: Triggered when that instance is successfully connected.
|
|
208
|
+
* **`client.isInit()`**: Returns that instance's connection status.
|
|
209
|
+
* **`client.destroy()`**: Destroy the connection maintained by that instance.
|
|
210
|
+
|
|
211
|
+
## ⚠️ Notes
|
|
212
|
+
|
|
213
|
+
1. **Same-Origin Policy**: While Penpal simplifies postMessage, please ensure `allowedOrigins` is correctly configured for security.
|
|
214
|
+
2. **Build Order**: During production builds, ensure files containing `defineBridge` are correctly processed. Usually, as long as these files are within your source tree (referenced via import), the Vite plugin will scan them.
|
|
215
|
+
3. **Serialization**: Function values passed directly or nested in arrays/plain objects are proxied automatically, so callback-style APIs can cross the bridge. DOM nodes and other non-transferable objects are still not supported.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
182
219
|
MIT
|
package/dist/full/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var T=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var ee=Object.prototype.hasOwnProperty;var te=(e,t)=>{for(var r in t)T(e,r,{get:t[r],enumerable:!0})},re=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Z(t))!ee.call(e,s)&&s!==r&&T(e,s,{get:()=>t[s],enumerable:!(n=Q(t,s))||n.enumerable});return e};var ne=e=>re(T({},"__esModule",{value:!0}),e);var Fe={};te(Fe,{default:()=>be,isInit:()=>He,offMessage:()=>b,onInit:()=>xe,onMessage:()=>ke});module.exports=ne(Fe);var se=class extends Error{code;constructor(e,t){super(t),this.name="PenpalError",this.code=e}},p=se,ae=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof p?e.code:void 0}),oe=({name:e,message:t,stack:r,penpalCode:n})=>{let s=n?new p(n,t):new Error(t);return s.name=e,s.stack=r,s},ie=Symbol("Reply"),de=class{value;transferables;#t=ie;constructor(e,t){this.value=e,this.transferables=t?.transferables}},le=de,f="penpal",S=e=>typeof e=="object"&&e!==null,V=e=>typeof e=="function",ce=e=>S(e)&&e.namespace===f,N=e=>e.type==="SYN",D=e=>e.type==="ACK1",O=e=>e.type==="ACK2",W=e=>e.type==="CALL",j=e=>e.type==="REPLY",he=e=>e.type==="DESTROY",z=(e,t=[])=>{let r=[];for(let n of Object.keys(e)){let s=e[n];V(s)?r.push([...t,n]):S(s)&&r.push(...z(s,[...t,n]))}return r},ue=(e,t)=>{let r=e.reduce((n,s)=>S(n)?n[s]:void 0,t);return V(r)?r:void 0},y=e=>e.join("."),F=(e,t,r)=>({namespace:f,channel:e,type:"REPLY",callId:t,isError:!0,...r instanceof Error?{value:ae(r),isSerializedErrorInstance:!0}:{value:r}}),fe=(e,t,r,n)=>{let s=!1,l=async u=>{if(s||!W(u))return;n?.(`Received ${y(u.methodPath)}() call`,u);let{methodPath:v,args:c,id:o}=u,a,M;try{let d=ue(v,t);if(!d)throw new p("METHOD_NOT_FOUND",`Method \`${y(v)}\` is not found.`);let h=await d(...c);h instanceof le&&(M=h.transferables,h=await h.value),a={namespace:f,channel:r,type:"REPLY",callId:o,value:h}}catch(d){a=F(r,o,d)}if(!s)try{n?.(`Sending ${y(v)}() reply`,a),e.sendMessage(a,M)}catch(d){throw d.name==="DataCloneError"&&(a=F(r,o,d),n?.(`Sending ${y(v)}() reply`,a),e.sendMessage(a)),d}};return e.addMessageHandler(l),()=>{s=!0,e.removeMessageHandler(l)}},pe=fe,K=crypto.randomUUID?.bind(crypto)??(()=>new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")),ve=Symbol("CallOptions"),Me=class{transferables;timeout;#t=ve;constructor(e){this.transferables=e?.transferables,this.timeout=e?.timeout}},ye=Me,ge=new Set(["apply","call","bind"]),G=(e,t,r=[])=>new Proxy(r.length?()=>{}:Object.create(null),{get(n,s){if(s!=="then")return r.length&&ge.has(s)?Reflect.get(n,s):G(e,t,[...r,s])},apply(n,s,l){return e(r,l)}}),U=e=>new p("CONNECTION_DESTROYED",`Method call ${y(e)}() failed due to destroyed connection`),Ee=(e,t,r)=>{let n=!1,s=new Map,l=c=>{if(!j(c))return;let{callId:o,value:a,isError:M,isSerializedErrorInstance:d}=c,h=s.get(o);h&&(s.delete(o),r?.(`Received ${y(h.methodPath)}() call`,c),M?h.reject(d?oe(a):a):h.resolve(a))};return e.addMessageHandler(l),{remoteProxy:G((c,o)=>{if(n)throw U(c);let a=K(),M=o[o.length-1],d=M instanceof ye,{timeout:h,transferables:_}=d?M:{},m=d?o.slice(0,-1):o;return new Promise((A,w)=>{let R=h!==void 0?window.setTimeout(()=>{s.delete(a),w(new p("METHOD_CALL_TIMEOUT",`Method call ${y(c)}() timed out after ${h}ms`))},h):void 0;s.set(a,{methodPath:c,resolve:A,reject:w,timeoutId:R});try{let E={namespace:f,channel:t,type:"CALL",id:a,methodPath:c,args:m};r?.(`Sending ${y(c)}() call`,E),e.sendMessage(E,_)}catch(E){w(new p("TRANSMISSION_FAILED",E.message))}})},r),destroy:()=>{n=!0,e.removeMessageHandler(l);for(let{methodPath:c,reject:o,timeoutId:a}of s.values())clearTimeout(a),o(U(c));s.clear()}}},we=Ee,Ie=()=>{let e,t;return{promise:new Promise((n,s)=>{e=n,t=s}),resolve:e,reject:t}},me=Ie,Ae=class extends Error{constructor(e){super(`You've hit a bug in Penpal. Please file an issue with the following information: ${e}`)}},P=Ae,L="deprecated-penpal",Ce=e=>S(e)&&"penpal"in e,Ne=e=>e.split("."),Y=e=>e.join("."),B=e=>new P(`Unexpected message to translate: ${JSON.stringify(e)}`),Pe=e=>{if(e.penpal==="syn")return{namespace:f,channel:void 0,type:"SYN",participantId:L};if(e.penpal==="ack")return{namespace:f,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:f,channel:void 0,type:"CALL",id:e.id,methodPath:Ne(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:f,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:f,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw B(e)},Se=e=>{if(D(e))return{penpal:"synAck",methodNames:e.methodPaths.map(Y)};if(W(e))return{penpal:"call",id:e.id,methodName:Y(e.methodPath),args:e.args};if(j(e))return e.isError?{penpal:"reply",id:e.callId,resolution:"rejected",...e.isSerializedErrorInstance?{returnValue:e.value,returnValueIsError:!0}:{returnValue:e.value}}:{penpal:"reply",id:e.callId,resolution:"fulfilled",returnValue:e.value};throw B(e)},_e=({messenger:e,methods:t,timeout:r,channel:n,log:s})=>{let l=K(),u,v=[],c=!1,o=z(t),{promise:a,resolve:M,reject:d}=me(),h=r!==void 0?setTimeout(()=>{d(new p("CONNECTION_TIMEOUT",`Connection timed out after ${r}ms`))},r):void 0,_=()=>{for(let i of v)i()},m=()=>{if(c)return;v.push(pe(e,t,n,s));let{remoteProxy:i,destroy:g}=we(e,n,s);v.push(g),clearTimeout(h),c=!0,M({remoteProxy:i,destroy:_})},A=()=>{let i={namespace:f,type:"SYN",channel:n,participantId:l};s?.("Sending handshake SYN",i);try{e.sendMessage(i)}catch(g){d(new p("TRANSMISSION_FAILED",g.message))}},w=i=>{if(s?.("Received handshake SYN",i),i.participantId===u&&u!==L||(u=i.participantId,A(),!(l>u||u===L)))return;let C={namespace:f,channel:n,type:"ACK1",methodPaths:o};s?.("Sending handshake ACK1",C);try{e.sendMessage(C)}catch(q){d(new p("TRANSMISSION_FAILED",q.message));return}},R=i=>{s?.("Received handshake ACK1",i);let g={namespace:f,channel:n,type:"ACK2"};s?.("Sending handshake ACK2",g);try{e.sendMessage(g)}catch(C){d(new p("TRANSMISSION_FAILED",C.message));return}m()},E=i=>{s?.("Received handshake ACK2",i),m()},x=i=>{N(i)&&w(i),D(i)&&R(i),O(i)&&E(i)};return e.addMessageHandler(x),v.push(()=>e.removeMessageHandler(x)),A(),a},Re=_e,Te=e=>{let t=!1,r;return(...n)=>(t||(t=!0,r=e(...n)),r)},Oe=Te,$=new WeakSet,Le=({messenger:e,methods:t={},timeout:r,channel:n,log:s})=>{if(!e)throw new p("INVALID_ARGUMENT","messenger must be defined");if($.has(e))throw new p("INVALID_ARGUMENT","A messenger can only be used for a single connection");$.add(e);let l=[e.destroy],u=Oe(o=>{if(o){let a={namespace:f,channel:n,type:"DESTROY"};try{e.sendMessage(a)}catch{}}for(let a of l)a();s?.("Connection destroyed")}),v=o=>ce(o)&&o.channel===n;return{promise:(async()=>{try{e.initialize({log:s,validateReceivedMessage:v}),e.addMessageHandler(M=>{he(M)&&u(!1)});let{remoteProxy:o,destroy:a}=await Re({messenger:e,methods:t,timeout:r,channel:n,log:s});return l.push(a),o}catch(o){throw u(!0),o}})(),destroy:()=>{u(!0)}}},J=Le,De=class{#t;#n;#o;#i;#s;#r=new Set;#e;#a=!1;constructor({remoteWindow:e,allowedOrigins:t}){if(!e)throw new p("INVALID_ARGUMENT","remoteWindow must be defined");this.#t=e,this.#n=t?.length?t:[window.origin]}initialize=({log:e,validateReceivedMessage:t})=>{this.#o=e,this.#i=t,window.addEventListener("message",this.#h)};sendMessage=(e,t)=>{if(N(e)){let r=this.#d(e);this.#t.postMessage(e,{targetOrigin:r,transfer:t});return}if(D(e)||this.#a){let r=this.#a?Se(e):e,n=this.#d(e);this.#t.postMessage(r,{targetOrigin:n,transfer:t});return}if(O(e)){let{port1:r,port2:n}=new MessageChannel;this.#e=r,r.addEventListener("message",this.#l),r.start();let s=[n,...t||[]],l=this.#d(e);this.#t.postMessage(e,{targetOrigin:l,transfer:s});return}if(this.#e){this.#e.postMessage(e,{transfer:t});return}throw new P("Port is undefined")};addMessageHandler=e=>{this.#r.add(e)};removeMessageHandler=e=>{this.#r.delete(e)};destroy=()=>{window.removeEventListener("message",this.#h),this.#c(),this.#r.clear()};#u=e=>this.#n.some(t=>t instanceof RegExp?t.test(e):t===e||t==="*");#d=e=>{if(N(e))return"*";if(!this.#s)throw new P("Concrete remote origin not set");return this.#s==="null"&&this.#n.includes("*")?"*":this.#s};#c=()=>{this.#e?.removeEventListener("message",this.#l),this.#e?.close(),this.#e=void 0};#h=({source:e,origin:t,ports:r,data:n})=>{if(e===this.#t&&(Ce(n)&&(this.#o?.("Please upgrade the child window to the latest version of Penpal."),this.#a=!0,n=Pe(n)),!!this.#i?.(n))){if(!this.#u(t)){this.#o?.(`Received a message from origin \`${t}\` which did not match allowed origins \`[${this.#n.join(", ")}]\``);return}if(N(n)&&(this.#c(),this.#s=t),O(n)&&!this.#a){if(this.#e=r[0],!this.#e)throw new P("No port received on ACK2");this.#e.addEventListener("message",this.#l),this.#e.start()}for(let s of this.#r)s(n)}};#l=({data:e})=>{if(this.#i?.(e))for(let t of this.#r)t(e)}},X=De;var I=new Map,k=J({messenger:new X({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(e,t){let r=I.get(e);if(r)return r.forEach(n=>n(t)),!0}}}),be=new Proxy({},{get(e,t){return async r=>await k.promise.then(n=>n[t](r))}}),ke=(e,t,r)=>{let n=r?(l=>{t(l),b(e,t)}):t,s=I.get(e);return s?s.add(n):I.set(e,new Set([n])),()=>b(e,n)},b=(e,t)=>{if(!t){I.delete(e);return}let r=I.get(e);r&&r.delete(t)},H=!1;k.promise.then(()=>{H=!0});var He=()=>H,xe=e=>{if(H){e();return}k.promise.then(()=>{e()})};0&&(module.exports={isInit,offMessage,onInit,onMessage});
|
|
1
|
+
"use strict";var P=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var se=Object.prototype.hasOwnProperty;var ie=(e,t)=>{for(var r in t)P(e,r,{get:t[r],enumerable:!0})},oe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of ne(t))!se.call(e,s)&&s!==r&&P(e,s,{get:()=>t[s],enumerable:!(n=re(t,s))||n.enumerable});return e};var ae=e=>oe(P({},"__esModule",{value:!0}),e);var $e={};ie($e,{createBridgeClient:()=>ee,default:()=>We});module.exports=ae($e);var ce=class extends Error{code;constructor(e,t){super(t),this.name="PenpalError",this.code=e}},y=ce,de=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof y?e.code:void 0}),le=({name:e,message:t,stack:r,penpalCode:n})=>{let s=n?new y(n,t):new Error(t);return s.name=e,s.stack=r,s},he=Symbol("Reply"),ue=class{value;transferables;#t=he;constructor(e,t){this.value=e,this.transferables=t?.transferables}},fe=ue,g="penpal",R=e=>typeof e=="object"&&e!==null,$=e=>typeof e=="function",pe=e=>R(e)&&e.namespace===g,C=e=>e.type==="SYN",N=e=>e.type==="ACK1",S=e=>e.type==="ACK2",U=e=>e.type==="CALL",z=e=>e.type==="REPLY",ye=e=>e.type==="DESTROY",V=(e,t=[])=>{let r=[];for(let n of Object.keys(e)){let s=e[n];$(s)?r.push([...t,n]):R(s)&&r.push(...V(s,[...t,n]))}return r},ge=(e,t)=>{let r=e.reduce((n,s)=>R(n)?n[s]:void 0,t);return $(r)?r:void 0},m=e=>e.join("."),H=(e,t,r)=>({namespace:g,channel:e,type:"REPLY",callId:t,isError:!0,...r instanceof Error?{value:de(r),isSerializedErrorInstance:!0}:{value:r}}),Me=(e,t,r,n)=>{let s=!1,h=async d=>{if(s||!U(d))return;n?.(`Received ${m(d.methodPath)}() call`,d);let{methodPath:f,args:p,id:l}=d,i,a;try{let c=ge(f,t);if(!c)throw new y("METHOD_NOT_FOUND",`Method \`${m(f)}\` is not found.`);let o=await c(...p);o instanceof fe&&(a=o.transferables,o=await o.value),i={namespace:g,channel:r,type:"REPLY",callId:l,value:o}}catch(c){i=H(r,l,c)}if(!s)try{n?.(`Sending ${m(f)}() reply`,i),e.sendMessage(i,a)}catch(c){throw c.name==="DataCloneError"&&(i=H(r,l,c),n?.(`Sending ${m(f)}() reply`,i),e.sendMessage(i)),c}};return e.addMessageHandler(h),()=>{s=!0,e.removeMessageHandler(h)}},ve=Me,Y=crypto.randomUUID?.bind(crypto)??(()=>new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")),me=Symbol("CallOptions"),we=class{transferables;timeout;#t=me;constructor(e){this.transferables=e?.transferables,this.timeout=e?.timeout}},be=we,Ie=new Set(["apply","call","bind"]),B=(e,t,r=[])=>new Proxy(r.length?()=>{}:Object.create(null),{get(n,s){if(s!=="then")return r.length&&Ie.has(s)?Reflect.get(n,s):B(e,t,[...r,s])},apply(n,s,h){return e(r,h)}}),x=e=>new y("CONNECTION_DESTROYED",`Method call ${m(e)}() failed due to destroyed connection`),Ee=(e,t,r)=>{let n=!1,s=new Map,h=p=>{if(!z(p))return;let{callId:l,value:i,isError:a,isSerializedErrorInstance:c}=p,o=s.get(l);o&&(s.delete(l),r?.(`Received ${m(o.methodPath)}() call`,p),a?o.reject(c?le(i):i):o.resolve(i))};return e.addMessageHandler(h),{remoteProxy:B((p,l)=>{if(n)throw x(p);let i=Y(),a=l[l.length-1],c=a instanceof be,{timeout:o,transferables:M}=c?a:{},v=c?l.slice(0,-1):l;return new Promise((b,E)=>{let A=o!==void 0?window.setTimeout(()=>{s.delete(i),E(new y("METHOD_CALL_TIMEOUT",`Method call ${m(p)}() timed out after ${o}ms`))},o):void 0;s.set(i,{methodPath:p,resolve:b,reject:E,timeoutId:A});try{let I={namespace:g,channel:t,type:"CALL",id:i,methodPath:p,args:v};r?.(`Sending ${m(p)}() call`,I),e.sendMessage(I,M)}catch(I){E(new y("TRANSMISSION_FAILED",I.message))}})},r),destroy:()=>{n=!0,e.removeMessageHandler(h);for(let{methodPath:p,reject:l,timeoutId:i}of s.values())clearTimeout(i),l(x(p));s.clear()}}},ke=Ee,Ce=()=>{let e,t;return{promise:new Promise((n,s)=>{e=n,t=s}),resolve:e,reject:t}},Re=Ce,_="deprecated-penpal",Ae=e=>R(e)&&"penpal"in e,Pe=e=>e.split("."),j=e=>e.join("."),Se=e=>{try{return JSON.stringify(e)}catch{return String(e)}},K=e=>new y("TRANSMISSION_FAILED",`Unexpected message to translate: ${Se(e)}`),_e=e=>{if(e.penpal==="syn")return{namespace:g,channel:void 0,type:"SYN",participantId:_};if(e.penpal==="ack")return{namespace:g,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:g,channel:void 0,type:"CALL",id:e.id,methodPath:Pe(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:g,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:g,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw K(e)},Ne=e=>{if(N(e))return{penpal:"synAck",methodNames:e.methodPaths.map(j)};if(U(e))return{penpal:"call",id:e.id,methodName:j(e.methodPath),args:e.args};if(z(e))return e.isError?{penpal:"reply",id:e.callId,resolution:"rejected",...e.isSerializedErrorInstance?{returnValue:e.value,returnValueIsError:!0}:{returnValue:e.value}}:{penpal:"reply",id:e.callId,resolution:"fulfilled",returnValue:e.value};throw K(e)},Te=({messenger:e,methods:t,timeout:r,channel:n,log:s})=>{let h=Y(),d,f=[],p=!1,l=V(t),{promise:i,resolve:a,reject:c}=Re(),o=r!==void 0?setTimeout(()=>{c(new y("CONNECTION_TIMEOUT",`Connection timed out after ${r}ms`))},r):void 0,M=()=>{for(let u of f)u()},v=()=>{if(p)return;f.push(ve(e,t,n,s));let{remoteProxy:u,destroy:w}=ke(e,n,s);f.push(w),clearTimeout(o),p=!0,a({remoteProxy:u,destroy:M})},b=()=>{let u={namespace:g,type:"SYN",channel:n,participantId:h};s?.("Sending handshake SYN",u);try{e.sendMessage(u)}catch(w){c(new y("TRANSMISSION_FAILED",w.message))}},E=u=>{if(s?.("Received handshake SYN",u),u.participantId===d&&d!==_||(d=u.participantId,b(),!(h>d||d===_)))return;let k={namespace:g,channel:n,type:"ACK1",methodPaths:l};s?.("Sending handshake ACK1",k);try{e.sendMessage(k)}catch(te){c(new y("TRANSMISSION_FAILED",te.message));return}},A=u=>{s?.("Received handshake ACK1",u);let w={namespace:g,channel:n,type:"ACK2"};s?.("Sending handshake ACK2",w);try{e.sendMessage(w)}catch(k){c(new y("TRANSMISSION_FAILED",k.message));return}v()},I=u=>{s?.("Received handshake ACK2",u),v()},F=u=>{C(u)&&E(u),N(u)&&A(u),S(u)&&I(u)};return e.addMessageHandler(F),f.push(()=>e.removeMessageHandler(F)),b(),i},Oe=Te,Le=e=>{let t=!1,r;return(...n)=>(t||(t=!0,r=e(...n)),r)},De=Le,W=new WeakSet,Fe=({messenger:e,methods:t={},timeout:r,channel:n,log:s})=>{if(!e)throw new y("INVALID_ARGUMENT","messenger must be defined");if(W.has(e))throw new y("INVALID_ARGUMENT","A messenger can only be used for a single connection");W.add(e);let h=[e.destroy],d=De(l=>{if(l){let i={namespace:g,channel:n,type:"DESTROY"};try{e.sendMessage(i)}catch{}}for(let i of h)i();s?.("Connection destroyed")}),f=l=>pe(l)&&l.channel===n;return{promise:(async()=>{try{e.initialize({log:s,validateReceivedMessage:f}),e.addMessageHandler(a=>{ye(a)&&d(!1)});let{remoteProxy:l,destroy:i}=await Oe({messenger:e,methods:t,timeout:r,channel:n,log:s});return h.push(i),l}catch(l){throw d(!0),l}})(),destroy:()=>{d(!0)}}},G=Fe,He=class{#t;#s;#r;#a;#i;#n=new Set;#e;#o=!1;constructor({remoteWindow:e,allowedOrigins:t}){if(!e)throw new y("INVALID_ARGUMENT","remoteWindow must be defined");this.#t=e,this.#s=t?.length?t:[window.origin]}initialize=({log:e,validateReceivedMessage:t})=>{this.#r=e,this.#a=t,window.addEventListener("message",this.#h)};sendMessage=(e,t)=>{if(C(e)){let r=this.#c(e);this.#t.postMessage(e,{targetOrigin:r,transfer:t});return}if(N(e)||this.#o){let r=this.#o?Ne(e):e,n=this.#c(e);this.#t.postMessage(r,{targetOrigin:n,transfer:t});return}if(S(e)){let{port1:r,port2:n}=new MessageChannel;this.#e=r,r.addEventListener("message",this.#d),r.start();let s=[n,...t||[]],h=this.#c(e);this.#t.postMessage(e,{targetOrigin:h,transfer:s});return}if(this.#e){this.#e.postMessage(e,{transfer:t});return}throw new y("TRANSMISSION_FAILED","Cannot send message because the MessagePort is not connected")};addMessageHandler=e=>{this.#n.add(e)};removeMessageHandler=e=>{this.#n.delete(e)};destroy=()=>{window.removeEventListener("message",this.#h),this.#l(),this.#n.clear()};#u=e=>this.#s.some(t=>t instanceof RegExp?t.test(e):t===e||t==="*");#c=e=>{if(C(e))return"*";if(!this.#i)throw new y("TRANSMISSION_FAILED","Cannot send message because the remote origin is not established");return this.#i==="null"&&this.#s.includes("*")?"*":this.#i};#l=()=>{this.#e?.removeEventListener("message",this.#d),this.#e?.close(),this.#e=void 0};#h=({source:e,origin:t,ports:r,data:n})=>{if(e===this.#t){if(Ae(n)){this.#r?.("Please upgrade the child window to the latest version of Penpal."),this.#o=!0;try{n=_e(n)}catch(s){this.#r?.(`Failed to translate deprecated message: ${s.message}`);return}}if(this.#a?.(n)){if(!this.#u(t)){this.#r?.(`Received a message from origin \`${t}\` which did not match allowed origins \`[${this.#s.join(", ")}]\``);return}if(C(n)&&(this.#l(),this.#i=t),S(n)&&!this.#o){if(this.#e=r[0],!this.#e){this.#r?.("Ignoring ACK2 because it did not include a MessagePort");return}this.#e.addEventListener("message",this.#d),this.#e.start()}for(let s of this.#n)s(n)}}};#d=({data:e})=>{if(this.#a?.(e))for(let t of this.#n)t(e)}},J=He;var q="iframe-bridge-kit.callback",O="__iframeBridgeInvokeCallback",T=e=>typeof e=="object"&&e!==null,X=e=>{let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},xe=e=>T(e)&&e.__iframeBridgeType===q&&typeof e.id=="string",Q=e=>{let t=new Map,r=new WeakMap,n=new Map,s=0,h=i=>{let a=r.get(i);return a||(a=`${Date.now().toString(36)}-${(++s).toString(36)}`,r.set(i,a)),t.set(a,i),{__iframeBridgeType:q,id:a}},d=(i,a=new WeakMap)=>{if(typeof i=="function")return h(i);if(!T(i))return i;if(a.has(i))return a.get(i);if(Array.isArray(i)){let o=[];return a.set(i,o),i.forEach((M,v)=>{o[v]=d(M,a)}),o}if(!X(i))return i;let c={};return a.set(i,c),Object.keys(i).forEach(o=>{c[o]=d(i[o],a)}),c},f=(i,a=new WeakMap)=>{if(!T(i))return i;if(xe(i)){let o=n.get(i.id);return o||(o=async(...M)=>{let b=await(await e())[O](i.id,d(M));return f(b)},n.set(i.id,o)),o}if(a.has(i))return a.get(i);if(Array.isArray(i)){let o=[];return a.set(i,o),i.forEach((M,v)=>{o[v]=f(M,a)}),o}if(!X(i))return i;let c={};return a.set(i,c),Object.keys(i).forEach(o=>{c[o]=f(i[o],a)}),c};return{serialize:d,deserialize:f,invokeLocalCallback:async(i,a)=>{let c=t.get(i);if(!c)throw new Error(`Callback "${i}" is not available`);let o=await c(...f(a));return d(o)},clearCallbacks:()=>{t.clear(),n.clear()}}};var je="iframe-bridge-channel",Z=["__AllowedOrigins__"],D=class{msgProxy=new Map;initCallbacks=new Set;conn;remotePromise;inited=!1;connectionId=0;callbacks=Q(()=>this.getRemote());api;constructor(){let t={onMessage:this.onMessage,offMessage:this.offMessage,isInit:this.isInit,onInit:this.onInit,destroy:this.destroy};this.api=new Proxy({},{get:(r,n)=>{if(n!=="then"&&typeof n=="string")return n in t?t[n]:async(...s)=>{let d=(await this.getRemote())[n];if(typeof d!="function")throw new Error(`Remote method "${String(n)}" is not available`);return this.callbacks.deserialize(await d(...this.callbacks.serialize(s)))}}})}connect=(t,r=Z)=>{this.conn?.destroy(),this.inited=!1;let n=++this.connectionId;return this.conn=G({messenger:new J({remoteWindow:t,allowedOrigins:r}),channel:je,methods:{onMessage:this.receiveMessage,[O]:this.callbacks.invokeLocalCallback}}),this.remotePromise=this.conn.promise.then(s=>(n===this.connectionId&&(this.inited=!0,this.notifyInit()),s)),this.remotePromise};getRemote=()=>{if(!this.remotePromise){if(typeof window>"u"||window.parent===window)throw new Error("remoteWindow is not configured. Pass a Window when creating the bridge client.");return this.connect(window.parent)}return this.remotePromise};receiveMessage=(t,r)=>{let n=this.msgProxy.get(t);if(n){let s=this.callbacks.deserialize(r);return n.forEach(h=>h(s)),!0}};notifyInit=()=>{let t=Array.from(this.initCallbacks);this.initCallbacks.clear(),t.forEach(r=>r(this.api))};onMessage=(t,r,n)=>{let s=n?(d=>{r(d),this.offMessage(t,s)}):r,h=this.msgProxy.get(t);return h?h.add(s):this.msgProxy.set(t,new Set([s])),()=>this.offMessage(t,s)};offMessage=(t,r)=>{if(!r){this.msgProxy.delete(t);return}let n=this.msgProxy.get(t);n&&n.delete(r)};isInit=()=>this.inited;onInit=t=>{if(this.inited){t(this.api);return}this.initCallbacks.add(t)};destroy=()=>{this.connectionId++,this.conn?.destroy(),this.conn=void 0,this.remotePromise=void 0,this.inited=!1,this.initCallbacks.clear(),this.callbacks.clearCallbacks()}},ee=(e,t=Z)=>{let r=new D;return r.connect(e,t),r.api},L,We=()=>(L||(L=ee(window.parent)),L);0&&(module.exports={createBridgeClient});
|
package/dist/full/core.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var q=class extends Error{code;constructor(e,t){super(t),this.name="PenpalError",this.code=e}},p=q,Q=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof p?e.code:void 0}),Z=({name:e,message:t,stack:r,penpalCode:n})=>{let s=n?new p(n,t):new Error(t);return s.name=e,s.stack=r,s},ee=Symbol("Reply"),te=class{value;transferables;#t=ee;constructor(e,t){this.value=e,this.transferables=t?.transferables}},re=te,f="penpal",S=e=>typeof e=="object"&&e!==null,Y=e=>typeof e=="function",ne=e=>S(e)&&e.namespace===f,N=e=>e.type==="SYN",L=e=>e.type==="ACK1",T=e=>e.type==="ACK2",$=e=>e.type==="CALL",V=e=>e.type==="REPLY",se=e=>e.type==="DESTROY",W=(e,t=[])=>{let r=[];for(let n of Object.keys(e)){let s=e[n];Y(s)?r.push([...t,n]):S(s)&&r.push(...W(s,[...t,n]))}return r},ae=(e,t)=>{let r=e.reduce((n,s)=>S(n)?n[s]:void 0,t);return Y(r)?r:void 0},y=e=>e.join("."),H=(e,t,r)=>({namespace:f,channel:e,type:"REPLY",callId:t,isError:!0,...r instanceof Error?{value:Q(r),isSerializedErrorInstance:!0}:{value:r}}),oe=(e,t,r,n)=>{let s=!1,l=async u=>{if(s||!$(u))return;n?.(`Received ${y(u.methodPath)}() call`,u);let{methodPath:v,args:c,id:o}=u,a,M;try{let d=ae(v,t);if(!d)throw new p("METHOD_NOT_FOUND",`Method \`${y(v)}\` is not found.`);let h=await d(...c);h instanceof re&&(M=h.transferables,h=await h.value),a={namespace:f,channel:r,type:"REPLY",callId:o,value:h}}catch(d){a=H(r,o,d)}if(!s)try{n?.(`Sending ${y(v)}() reply`,a),e.sendMessage(a,M)}catch(d){throw d.name==="DataCloneError"&&(a=H(r,o,d),n?.(`Sending ${y(v)}() reply`,a),e.sendMessage(a)),d}};return e.addMessageHandler(l),()=>{s=!0,e.removeMessageHandler(l)}},ie=oe,j=crypto.randomUUID?.bind(crypto)??(()=>new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")),de=Symbol("CallOptions"),le=class{transferables;timeout;#t=de;constructor(e){this.transferables=e?.transferables,this.timeout=e?.timeout}},ce=le,he=new Set(["apply","call","bind"]),z=(e,t,r=[])=>new Proxy(r.length?()=>{}:Object.create(null),{get(n,s){if(s!=="then")return r.length&&he.has(s)?Reflect.get(n,s):z(e,t,[...r,s])},apply(n,s,l){return e(r,l)}}),x=e=>new p("CONNECTION_DESTROYED",`Method call ${y(e)}() failed due to destroyed connection`),ue=(e,t,r)=>{let n=!1,s=new Map,l=c=>{if(!V(c))return;let{callId:o,value:a,isError:M,isSerializedErrorInstance:d}=c,h=s.get(o);h&&(s.delete(o),r?.(`Received ${y(h.methodPath)}() call`,c),M?h.reject(d?Z(a):a):h.resolve(a))};return e.addMessageHandler(l),{remoteProxy:z((c,o)=>{if(n)throw x(c);let a=j(),M=o[o.length-1],d=M instanceof ce,{timeout:h,transferables:_}=d?M:{},m=d?o.slice(0,-1):o;return new Promise((A,w)=>{let R=h!==void 0?window.setTimeout(()=>{s.delete(a),w(new p("METHOD_CALL_TIMEOUT",`Method call ${y(c)}() timed out after ${h}ms`))},h):void 0;s.set(a,{methodPath:c,resolve:A,reject:w,timeoutId:R});try{let E={namespace:f,channel:t,type:"CALL",id:a,methodPath:c,args:m};r?.(`Sending ${y(c)}() call`,E),e.sendMessage(E,_)}catch(E){w(new p("TRANSMISSION_FAILED",E.message))}})},r),destroy:()=>{n=!0,e.removeMessageHandler(l);for(let{methodPath:c,reject:o,timeoutId:a}of s.values())clearTimeout(a),o(x(c));s.clear()}}},fe=ue,pe=()=>{let e,t;return{promise:new Promise((n,s)=>{e=n,t=s}),resolve:e,reject:t}},ve=pe,Me=class extends Error{constructor(e){super(`You've hit a bug in Penpal. Please file an issue with the following information: ${e}`)}},P=Me,O="deprecated-penpal",ye=e=>S(e)&&"penpal"in e,ge=e=>e.split("."),F=e=>e.join("."),K=e=>new P(`Unexpected message to translate: ${JSON.stringify(e)}`),Ee=e=>{if(e.penpal==="syn")return{namespace:f,channel:void 0,type:"SYN",participantId:O};if(e.penpal==="ack")return{namespace:f,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:f,channel:void 0,type:"CALL",id:e.id,methodPath:ge(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:f,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:f,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw K(e)},we=e=>{if(L(e))return{penpal:"synAck",methodNames:e.methodPaths.map(F)};if($(e))return{penpal:"call",id:e.id,methodName:F(e.methodPath),args:e.args};if(V(e))return e.isError?{penpal:"reply",id:e.callId,resolution:"rejected",...e.isSerializedErrorInstance?{returnValue:e.value,returnValueIsError:!0}:{returnValue:e.value}}:{penpal:"reply",id:e.callId,resolution:"fulfilled",returnValue:e.value};throw K(e)},Ie=({messenger:e,methods:t,timeout:r,channel:n,log:s})=>{let l=j(),u,v=[],c=!1,o=W(t),{promise:a,resolve:M,reject:d}=ve(),h=r!==void 0?setTimeout(()=>{d(new p("CONNECTION_TIMEOUT",`Connection timed out after ${r}ms`))},r):void 0,_=()=>{for(let i of v)i()},m=()=>{if(c)return;v.push(ie(e,t,n,s));let{remoteProxy:i,destroy:g}=fe(e,n,s);v.push(g),clearTimeout(h),c=!0,M({remoteProxy:i,destroy:_})},A=()=>{let i={namespace:f,type:"SYN",channel:n,participantId:l};s?.("Sending handshake SYN",i);try{e.sendMessage(i)}catch(g){d(new p("TRANSMISSION_FAILED",g.message))}},w=i=>{if(s?.("Received handshake SYN",i),i.participantId===u&&u!==O||(u=i.participantId,A(),!(l>u||u===O)))return;let C={namespace:f,channel:n,type:"ACK1",methodPaths:o};s?.("Sending handshake ACK1",C);try{e.sendMessage(C)}catch(X){d(new p("TRANSMISSION_FAILED",X.message));return}},R=i=>{s?.("Received handshake ACK1",i);let g={namespace:f,channel:n,type:"ACK2"};s?.("Sending handshake ACK2",g);try{e.sendMessage(g)}catch(C){d(new p("TRANSMISSION_FAILED",C.message));return}m()},E=i=>{s?.("Received handshake ACK2",i),m()},k=i=>{N(i)&&w(i),L(i)&&R(i),T(i)&&E(i)};return e.addMessageHandler(k),v.push(()=>e.removeMessageHandler(k)),A(),a},me=Ie,Ae=e=>{let t=!1,r;return(...n)=>(t||(t=!0,r=e(...n)),r)},Ce=Ae,U=new WeakSet,Ne=({messenger:e,methods:t={},timeout:r,channel:n,log:s})=>{if(!e)throw new p("INVALID_ARGUMENT","messenger must be defined");if(U.has(e))throw new p("INVALID_ARGUMENT","A messenger can only be used for a single connection");U.add(e);let l=[e.destroy],u=Ce(o=>{if(o){let a={namespace:f,channel:n,type:"DESTROY"};try{e.sendMessage(a)}catch{}}for(let a of l)a();s?.("Connection destroyed")}),v=o=>ne(o)&&o.channel===n;return{promise:(async()=>{try{e.initialize({log:s,validateReceivedMessage:v}),e.addMessageHandler(M=>{se(M)&&u(!1)});let{remoteProxy:o,destroy:a}=await me({messenger:e,methods:t,timeout:r,channel:n,log:s});return l.push(a),o}catch(o){throw u(!0),o}})(),destroy:()=>{u(!0)}}},G=Ne,Pe=class{#t;#n;#o;#i;#s;#r=new Set;#e;#a=!1;constructor({remoteWindow:e,allowedOrigins:t}){if(!e)throw new p("INVALID_ARGUMENT","remoteWindow must be defined");this.#t=e,this.#n=t?.length?t:[window.origin]}initialize=({log:e,validateReceivedMessage:t})=>{this.#o=e,this.#i=t,window.addEventListener("message",this.#h)};sendMessage=(e,t)=>{if(N(e)){let r=this.#d(e);this.#t.postMessage(e,{targetOrigin:r,transfer:t});return}if(L(e)||this.#a){let r=this.#a?we(e):e,n=this.#d(e);this.#t.postMessage(r,{targetOrigin:n,transfer:t});return}if(T(e)){let{port1:r,port2:n}=new MessageChannel;this.#e=r,r.addEventListener("message",this.#l),r.start();let s=[n,...t||[]],l=this.#d(e);this.#t.postMessage(e,{targetOrigin:l,transfer:s});return}if(this.#e){this.#e.postMessage(e,{transfer:t});return}throw new P("Port is undefined")};addMessageHandler=e=>{this.#r.add(e)};removeMessageHandler=e=>{this.#r.delete(e)};destroy=()=>{window.removeEventListener("message",this.#h),this.#c(),this.#r.clear()};#u=e=>this.#n.some(t=>t instanceof RegExp?t.test(e):t===e||t==="*");#d=e=>{if(N(e))return"*";if(!this.#s)throw new P("Concrete remote origin not set");return this.#s==="null"&&this.#n.includes("*")?"*":this.#s};#c=()=>{this.#e?.removeEventListener("message",this.#l),this.#e?.close(),this.#e=void 0};#h=({source:e,origin:t,ports:r,data:n})=>{if(e===this.#t&&(ye(n)&&(this.#o?.("Please upgrade the child window to the latest version of Penpal."),this.#a=!0,n=Ee(n)),!!this.#i?.(n))){if(!this.#u(t)){this.#o?.(`Received a message from origin \`${t}\` which did not match allowed origins \`[${this.#n.join(", ")}]\``);return}if(N(n)&&(this.#c(),this.#s=t),T(n)&&!this.#a){if(this.#e=r[0],!this.#e)throw new P("No port received on ACK2");this.#e.addEventListener("message",this.#l),this.#e.start()}for(let s of this.#r)s(n)}};#l=({data:e})=>{if(this.#i?.(e))for(let t of this.#r)t(e)}},B=Pe;var I=new Map,D=G({messenger:new B({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(e,t){let r=I.get(e);if(r)return r.forEach(n=>n(t)),!0}}}),be=new Proxy({},{get(e,t){return async r=>await D.promise.then(n=>n[t](r))}}),ke=(e,t,r)=>{let n=r?(l=>{t(l),J(e,t)}):t,s=I.get(e);return s?s.add(n):I.set(e,new Set([n])),()=>J(e,n)},J=(e,t)=>{if(!t){I.delete(e);return}let r=I.get(e);r&&r.delete(t)},b=!1;D.promise.then(()=>{b=!0});var He=()=>b,xe=e=>{if(b){e();return}D.promise.then(()=>{e()})};export{be as default,He as isInit,J as offMessage,xe as onInit,ke as onMessage};
|
|
1
|
+
var ee=class extends Error{code;constructor(e,t){super(t),this.name="PenpalError",this.code=e}},y=ee,te=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof y?e.code:void 0}),re=({name:e,message:t,stack:n,penpalCode:r})=>{let i=r?new y(r,t):new Error(t);return i.name=e,i.stack=n,i},ne=Symbol("Reply"),se=class{value;transferables;#t=ne;constructor(e,t){this.value=e,this.transferables=t?.transferables}},ie=se,g="penpal",R=e=>typeof e=="object"&&e!==null,W=e=>typeof e=="function",oe=e=>R(e)&&e.namespace===g,C=e=>e.type==="SYN",_=e=>e.type==="ACK1",P=e=>e.type==="ACK2",$=e=>e.type==="CALL",U=e=>e.type==="REPLY",ae=e=>e.type==="DESTROY",z=(e,t=[])=>{let n=[];for(let r of Object.keys(e)){let i=e[r];W(i)?n.push([...t,r]):R(i)&&n.push(...z(i,[...t,r]))}return n},ce=(e,t)=>{let n=e.reduce((r,i)=>R(r)?r[i]:void 0,t);return W(n)?n:void 0},m=e=>e.join("."),F=(e,t,n)=>({namespace:g,channel:e,type:"REPLY",callId:t,isError:!0,...n instanceof Error?{value:te(n),isSerializedErrorInstance:!0}:{value:n}}),de=(e,t,n,r)=>{let i=!1,h=async d=>{if(i||!$(d))return;r?.(`Received ${m(d.methodPath)}() call`,d);let{methodPath:f,args:p,id:l}=d,s,a;try{let c=ce(f,t);if(!c)throw new y("METHOD_NOT_FOUND",`Method \`${m(f)}\` is not found.`);let o=await c(...p);o instanceof ie&&(a=o.transferables,o=await o.value),s={namespace:g,channel:n,type:"REPLY",callId:l,value:o}}catch(c){s=F(n,l,c)}if(!i)try{r?.(`Sending ${m(f)}() reply`,s),e.sendMessage(s,a)}catch(c){throw c.name==="DataCloneError"&&(s=F(n,l,c),r?.(`Sending ${m(f)}() reply`,s),e.sendMessage(s)),c}};return e.addMessageHandler(h),()=>{i=!0,e.removeMessageHandler(h)}},le=de,V=crypto.randomUUID?.bind(crypto)??(()=>new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")),he=Symbol("CallOptions"),ue=class{transferables;timeout;#t=he;constructor(e){this.transferables=e?.transferables,this.timeout=e?.timeout}},fe=ue,pe=new Set(["apply","call","bind"]),Y=(e,t,n=[])=>new Proxy(n.length?()=>{}:Object.create(null),{get(r,i){if(i!=="then")return n.length&&pe.has(i)?Reflect.get(r,i):Y(e,t,[...n,i])},apply(r,i,h){return e(n,h)}}),H=e=>new y("CONNECTION_DESTROYED",`Method call ${m(e)}() failed due to destroyed connection`),ye=(e,t,n)=>{let r=!1,i=new Map,h=p=>{if(!U(p))return;let{callId:l,value:s,isError:a,isSerializedErrorInstance:c}=p,o=i.get(l);o&&(i.delete(l),n?.(`Received ${m(o.methodPath)}() call`,p),a?o.reject(c?re(s):s):o.resolve(s))};return e.addMessageHandler(h),{remoteProxy:Y((p,l)=>{if(r)throw H(p);let s=V(),a=l[l.length-1],c=a instanceof fe,{timeout:o,transferables:M}=c?a:{},v=c?l.slice(0,-1):l;return new Promise((b,E)=>{let A=o!==void 0?window.setTimeout(()=>{i.delete(s),E(new y("METHOD_CALL_TIMEOUT",`Method call ${m(p)}() timed out after ${o}ms`))},o):void 0;i.set(s,{methodPath:p,resolve:b,reject:E,timeoutId:A});try{let I={namespace:g,channel:t,type:"CALL",id:s,methodPath:p,args:v};n?.(`Sending ${m(p)}() call`,I),e.sendMessage(I,M)}catch(I){E(new y("TRANSMISSION_FAILED",I.message))}})},n),destroy:()=>{r=!0,e.removeMessageHandler(h);for(let{methodPath:p,reject:l,timeoutId:s}of i.values())clearTimeout(s),l(H(p));i.clear()}}},ge=ye,Me=()=>{let e,t;return{promise:new Promise((r,i)=>{e=r,t=i}),resolve:e,reject:t}},ve=Me,S="deprecated-penpal",me=e=>R(e)&&"penpal"in e,we=e=>e.split("."),x=e=>e.join("."),be=e=>{try{return JSON.stringify(e)}catch{return String(e)}},B=e=>new y("TRANSMISSION_FAILED",`Unexpected message to translate: ${be(e)}`),Ie=e=>{if(e.penpal==="syn")return{namespace:g,channel:void 0,type:"SYN",participantId:S};if(e.penpal==="ack")return{namespace:g,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:g,channel:void 0,type:"CALL",id:e.id,methodPath:we(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:g,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:g,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw B(e)},Ee=e=>{if(_(e))return{penpal:"synAck",methodNames:e.methodPaths.map(x)};if($(e))return{penpal:"call",id:e.id,methodName:x(e.methodPath),args:e.args};if(U(e))return e.isError?{penpal:"reply",id:e.callId,resolution:"rejected",...e.isSerializedErrorInstance?{returnValue:e.value,returnValueIsError:!0}:{returnValue:e.value}}:{penpal:"reply",id:e.callId,resolution:"fulfilled",returnValue:e.value};throw B(e)},ke=({messenger:e,methods:t,timeout:n,channel:r,log:i})=>{let h=V(),d,f=[],p=!1,l=z(t),{promise:s,resolve:a,reject:c}=ve(),o=n!==void 0?setTimeout(()=>{c(new y("CONNECTION_TIMEOUT",`Connection timed out after ${n}ms`))},n):void 0,M=()=>{for(let u of f)u()},v=()=>{if(p)return;f.push(le(e,t,r,i));let{remoteProxy:u,destroy:w}=ge(e,r,i);f.push(w),clearTimeout(o),p=!0,a({remoteProxy:u,destroy:M})},b=()=>{let u={namespace:g,type:"SYN",channel:r,participantId:h};i?.("Sending handshake SYN",u);try{e.sendMessage(u)}catch(w){c(new y("TRANSMISSION_FAILED",w.message))}},E=u=>{if(i?.("Received handshake SYN",u),u.participantId===d&&d!==S||(d=u.participantId,b(),!(h>d||d===S)))return;let k={namespace:g,channel:r,type:"ACK1",methodPaths:l};i?.("Sending handshake ACK1",k);try{e.sendMessage(k)}catch(Z){c(new y("TRANSMISSION_FAILED",Z.message));return}},A=u=>{i?.("Received handshake ACK1",u);let w={namespace:g,channel:r,type:"ACK2"};i?.("Sending handshake ACK2",w);try{e.sendMessage(w)}catch(k){c(new y("TRANSMISSION_FAILED",k.message));return}v()},I=u=>{i?.("Received handshake ACK2",u),v()},D=u=>{C(u)&&E(u),_(u)&&A(u),P(u)&&I(u)};return e.addMessageHandler(D),f.push(()=>e.removeMessageHandler(D)),b(),s},Ce=ke,Re=e=>{let t=!1,n;return(...r)=>(t||(t=!0,n=e(...r)),n)},Ae=Re,j=new WeakSet,Pe=({messenger:e,methods:t={},timeout:n,channel:r,log:i})=>{if(!e)throw new y("INVALID_ARGUMENT","messenger must be defined");if(j.has(e))throw new y("INVALID_ARGUMENT","A messenger can only be used for a single connection");j.add(e);let h=[e.destroy],d=Ae(l=>{if(l){let s={namespace:g,channel:r,type:"DESTROY"};try{e.sendMessage(s)}catch{}}for(let s of h)s();i?.("Connection destroyed")}),f=l=>oe(l)&&l.channel===r;return{promise:(async()=>{try{e.initialize({log:i,validateReceivedMessage:f}),e.addMessageHandler(a=>{ae(a)&&d(!1)});let{remoteProxy:l,destroy:s}=await Ce({messenger:e,methods:t,timeout:n,channel:r,log:i});return h.push(s),l}catch(l){throw d(!0),l}})(),destroy:()=>{d(!0)}}},K=Pe,Se=class{#t;#s;#r;#a;#i;#n=new Set;#e;#o=!1;constructor({remoteWindow:e,allowedOrigins:t}){if(!e)throw new y("INVALID_ARGUMENT","remoteWindow must be defined");this.#t=e,this.#s=t?.length?t:[window.origin]}initialize=({log:e,validateReceivedMessage:t})=>{this.#r=e,this.#a=t,window.addEventListener("message",this.#h)};sendMessage=(e,t)=>{if(C(e)){let n=this.#c(e);this.#t.postMessage(e,{targetOrigin:n,transfer:t});return}if(_(e)||this.#o){let n=this.#o?Ee(e):e,r=this.#c(e);this.#t.postMessage(n,{targetOrigin:r,transfer:t});return}if(P(e)){let{port1:n,port2:r}=new MessageChannel;this.#e=n,n.addEventListener("message",this.#d),n.start();let i=[r,...t||[]],h=this.#c(e);this.#t.postMessage(e,{targetOrigin:h,transfer:i});return}if(this.#e){this.#e.postMessage(e,{transfer:t});return}throw new y("TRANSMISSION_FAILED","Cannot send message because the MessagePort is not connected")};addMessageHandler=e=>{this.#n.add(e)};removeMessageHandler=e=>{this.#n.delete(e)};destroy=()=>{window.removeEventListener("message",this.#h),this.#l(),this.#n.clear()};#u=e=>this.#s.some(t=>t instanceof RegExp?t.test(e):t===e||t==="*");#c=e=>{if(C(e))return"*";if(!this.#i)throw new y("TRANSMISSION_FAILED","Cannot send message because the remote origin is not established");return this.#i==="null"&&this.#s.includes("*")?"*":this.#i};#l=()=>{this.#e?.removeEventListener("message",this.#d),this.#e?.close(),this.#e=void 0};#h=({source:e,origin:t,ports:n,data:r})=>{if(e===this.#t){if(me(r)){this.#r?.("Please upgrade the child window to the latest version of Penpal."),this.#o=!0;try{r=Ie(r)}catch(i){this.#r?.(`Failed to translate deprecated message: ${i.message}`);return}}if(this.#a?.(r)){if(!this.#u(t)){this.#r?.(`Received a message from origin \`${t}\` which did not match allowed origins \`[${this.#s.join(", ")}]\``);return}if(C(r)&&(this.#l(),this.#i=t),P(r)&&!this.#o){if(this.#e=n[0],!this.#e){this.#r?.("Ignoring ACK2 because it did not include a MessagePort");return}this.#e.addEventListener("message",this.#d),this.#e.start()}for(let i of this.#n)i(r)}}};#d=({data:e})=>{if(this.#a?.(e))for(let t of this.#n)t(e)}},G=Se;var X="iframe-bridge-kit.callback",T="__iframeBridgeInvokeCallback",N=e=>typeof e=="object"&&e!==null,J=e=>{let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},_e=e=>N(e)&&e.__iframeBridgeType===X&&typeof e.id=="string",q=e=>{let t=new Map,n=new WeakMap,r=new Map,i=0,h=s=>{let a=n.get(s);return a||(a=`${Date.now().toString(36)}-${(++i).toString(36)}`,n.set(s,a)),t.set(a,s),{__iframeBridgeType:X,id:a}},d=(s,a=new WeakMap)=>{if(typeof s=="function")return h(s);if(!N(s))return s;if(a.has(s))return a.get(s);if(Array.isArray(s)){let o=[];return a.set(s,o),s.forEach((M,v)=>{o[v]=d(M,a)}),o}if(!J(s))return s;let c={};return a.set(s,c),Object.keys(s).forEach(o=>{c[o]=d(s[o],a)}),c},f=(s,a=new WeakMap)=>{if(!N(s))return s;if(_e(s)){let o=r.get(s.id);return o||(o=async(...M)=>{let b=await(await e())[T](s.id,d(M));return f(b)},r.set(s.id,o)),o}if(a.has(s))return a.get(s);if(Array.isArray(s)){let o=[];return a.set(s,o),s.forEach((M,v)=>{o[v]=f(M,a)}),o}if(!J(s))return s;let c={};return a.set(s,c),Object.keys(s).forEach(o=>{c[o]=f(s[o],a)}),c};return{serialize:d,deserialize:f,invokeLocalCallback:async(s,a)=>{let c=t.get(s);if(!c)throw new Error(`Callback "${s}" is not available`);let o=await c(...f(a));return d(o)},clearCallbacks:()=>{t.clear(),r.clear()}}};var Ne="iframe-bridge-channel",Q=["__AllowedOrigins__"],L=class{msgProxy=new Map;initCallbacks=new Set;conn;remotePromise;inited=!1;connectionId=0;callbacks=q(()=>this.getRemote());api;constructor(){let t={onMessage:this.onMessage,offMessage:this.offMessage,isInit:this.isInit,onInit:this.onInit,destroy:this.destroy};this.api=new Proxy({},{get:(n,r)=>{if(r!=="then"&&typeof r=="string")return r in t?t[r]:async(...i)=>{let d=(await this.getRemote())[r];if(typeof d!="function")throw new Error(`Remote method "${String(r)}" is not available`);return this.callbacks.deserialize(await d(...this.callbacks.serialize(i)))}}})}connect=(t,n=Q)=>{this.conn?.destroy(),this.inited=!1;let r=++this.connectionId;return this.conn=K({messenger:new G({remoteWindow:t,allowedOrigins:n}),channel:Ne,methods:{onMessage:this.receiveMessage,[T]:this.callbacks.invokeLocalCallback}}),this.remotePromise=this.conn.promise.then(i=>(r===this.connectionId&&(this.inited=!0,this.notifyInit()),i)),this.remotePromise};getRemote=()=>{if(!this.remotePromise){if(typeof window>"u"||window.parent===window)throw new Error("remoteWindow is not configured. Pass a Window when creating the bridge client.");return this.connect(window.parent)}return this.remotePromise};receiveMessage=(t,n)=>{let r=this.msgProxy.get(t);if(r){let i=this.callbacks.deserialize(n);return r.forEach(h=>h(i)),!0}};notifyInit=()=>{let t=Array.from(this.initCallbacks);this.initCallbacks.clear(),t.forEach(n=>n(this.api))};onMessage=(t,n,r)=>{let i=r?(d=>{n(d),this.offMessage(t,i)}):n,h=this.msgProxy.get(t);return h?h.add(i):this.msgProxy.set(t,new Set([i])),()=>this.offMessage(t,i)};offMessage=(t,n)=>{if(!n){this.msgProxy.delete(t);return}let r=this.msgProxy.get(t);r&&r.delete(n)};isInit=()=>this.inited;onInit=t=>{if(this.inited){t(this.api);return}this.initCallbacks.add(t)};destroy=()=>{this.connectionId++,this.conn?.destroy(),this.conn=void 0,this.remotePromise=void 0,this.inited=!1,this.initCallbacks.clear(),this.callbacks.clearCallbacks()}},Te=(e,t=Q)=>{let n=new L;return n.connect(e,t),n.api},O,$e=()=>(O||(O=Te(window.parent)),O);export{Te as createBridgeClient,$e as default};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
type BridgeTarget = HTMLIFrameElement | Window;
|
|
1
2
|
/** 定义一个 bridge,暴露方法给 iframe 父/子窗口调用 */
|
|
2
|
-
declare const defineBridge: <TEmit extends Record<string, object | string | number | boolean | null | undefined>>(name: string, methods: Record<string, (...args: any[]) => any>) => {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
3
|
+
declare const defineBridge: <TEmit extends Record<string, object | string | number | boolean | null | undefined>>(name: string, methods: Record<string, (...args: any[]) => any>) => (target: BridgeTarget, allowedOrigins?: string[]) => Promise<{
|
|
4
|
+
emit<T extends keyof TEmit>(type: T, data: TEmit[T]): void;
|
|
5
|
+
destroy(): void;
|
|
6
|
+
}>;
|
|
7
7
|
|
|
8
8
|
export { defineBridge };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
type BridgeTarget = HTMLIFrameElement | Window;
|
|
1
2
|
/** 定义一个 bridge,暴露方法给 iframe 父/子窗口调用 */
|
|
2
|
-
declare const defineBridge: <TEmit extends Record<string, object | string | number | boolean | null | undefined>>(name: string, methods: Record<string, (...args: any[]) => any>) => {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
3
|
+
declare const defineBridge: <TEmit extends Record<string, object | string | number | boolean | null | undefined>>(name: string, methods: Record<string, (...args: any[]) => any>) => (target: BridgeTarget, allowedOrigins?: string[]) => Promise<{
|
|
4
|
+
emit<T extends keyof TEmit>(type: T, data: TEmit[T]): void;
|
|
5
|
+
destroy(): void;
|
|
6
|
+
}>;
|
|
7
7
|
|
|
8
8
|
export { defineBridge };
|
package/dist/index.js
CHANGED
|
@@ -24,27 +24,166 @@ __export(index_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
var import_penpal = require("penpal");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
|
|
28
|
+
// src/callbacks.ts
|
|
29
|
+
var callbackRefType = "iframe-bridge-kit.callback";
|
|
30
|
+
var callbackInvokeMethod = "__iframeBridgeInvokeCallback";
|
|
31
|
+
var isObject = (value) => typeof value === "object" && value !== null;
|
|
32
|
+
var isPlainObject = (value) => {
|
|
33
|
+
const proto = Object.getPrototypeOf(value);
|
|
34
|
+
return proto === Object.prototype || proto === null;
|
|
35
|
+
};
|
|
36
|
+
var isCallbackDescriptor = (value) => {
|
|
37
|
+
return isObject(value) && value.__iframeBridgeType === callbackRefType && typeof value.id === "string";
|
|
38
|
+
};
|
|
39
|
+
var createCallbackBridge = (getRemote) => {
|
|
40
|
+
const localCallbacks = /* @__PURE__ */ new Map();
|
|
41
|
+
const localCallbackIds = /* @__PURE__ */ new WeakMap();
|
|
42
|
+
const remoteCallbacks = /* @__PURE__ */ new Map();
|
|
43
|
+
let nextCallbackId = 0;
|
|
44
|
+
const registerLocalCallback = (fn) => {
|
|
45
|
+
let id = localCallbackIds.get(fn);
|
|
46
|
+
if (!id) {
|
|
47
|
+
id = `${Date.now().toString(36)}-${(++nextCallbackId).toString(36)}`;
|
|
48
|
+
localCallbackIds.set(fn, id);
|
|
49
|
+
}
|
|
50
|
+
localCallbacks.set(id, fn);
|
|
51
|
+
return {
|
|
52
|
+
__iframeBridgeType: callbackRefType,
|
|
53
|
+
id
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const serialize = (value, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
57
|
+
if (typeof value === "function") {
|
|
58
|
+
return registerLocalCallback(value);
|
|
59
|
+
}
|
|
60
|
+
if (!isObject(value)) {
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
if (seen.has(value)) {
|
|
64
|
+
return seen.get(value);
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
const copy2 = [];
|
|
68
|
+
seen.set(value, copy2);
|
|
69
|
+
value.forEach((item, index) => {
|
|
70
|
+
copy2[index] = serialize(item, seen);
|
|
71
|
+
});
|
|
72
|
+
return copy2;
|
|
73
|
+
}
|
|
74
|
+
if (!isPlainObject(value)) {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
const copy = {};
|
|
78
|
+
seen.set(value, copy);
|
|
79
|
+
Object.keys(value).forEach((key) => {
|
|
80
|
+
copy[key] = serialize(value[key], seen);
|
|
81
|
+
});
|
|
82
|
+
return copy;
|
|
83
|
+
};
|
|
84
|
+
const deserialize = (value, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
85
|
+
if (!isObject(value)) {
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
if (isCallbackDescriptor(value)) {
|
|
89
|
+
let callback = remoteCallbacks.get(value.id);
|
|
90
|
+
if (!callback) {
|
|
91
|
+
callback = async (...args) => {
|
|
92
|
+
const remote = await getRemote();
|
|
93
|
+
const result = await remote[callbackInvokeMethod](value.id, serialize(args));
|
|
94
|
+
return deserialize(result);
|
|
95
|
+
};
|
|
96
|
+
remoteCallbacks.set(value.id, callback);
|
|
32
97
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
98
|
+
return callback;
|
|
99
|
+
}
|
|
100
|
+
if (seen.has(value)) {
|
|
101
|
+
return seen.get(value);
|
|
102
|
+
}
|
|
103
|
+
if (Array.isArray(value)) {
|
|
104
|
+
const copy2 = [];
|
|
105
|
+
seen.set(value, copy2);
|
|
106
|
+
value.forEach((item, index) => {
|
|
107
|
+
copy2[index] = deserialize(item, seen);
|
|
40
108
|
});
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
emit(type, data) {
|
|
44
|
-
remote.onMessage(type, data);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
109
|
+
return copy2;
|
|
47
110
|
}
|
|
111
|
+
if (!isPlainObject(value)) {
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
const copy = {};
|
|
115
|
+
seen.set(value, copy);
|
|
116
|
+
Object.keys(value).forEach((key) => {
|
|
117
|
+
copy[key] = deserialize(value[key], seen);
|
|
118
|
+
});
|
|
119
|
+
return copy;
|
|
120
|
+
};
|
|
121
|
+
const invokeLocalCallback = async (id, args) => {
|
|
122
|
+
const callback = localCallbacks.get(id);
|
|
123
|
+
if (!callback) {
|
|
124
|
+
throw new Error(`Callback "${id}" is not available`);
|
|
125
|
+
}
|
|
126
|
+
const result = await callback(...deserialize(args));
|
|
127
|
+
return serialize(result);
|
|
128
|
+
};
|
|
129
|
+
const clearCallbacks = () => {
|
|
130
|
+
localCallbacks.clear();
|
|
131
|
+
remoteCallbacks.clear();
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
serialize,
|
|
135
|
+
deserialize,
|
|
136
|
+
invokeLocalCallback,
|
|
137
|
+
clearCallbacks
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/index.ts
|
|
142
|
+
var resolveRemoteWindow = (target) => {
|
|
143
|
+
if (typeof HTMLIFrameElement !== "undefined" && target instanceof HTMLIFrameElement) {
|
|
144
|
+
if (!target.contentWindow) {
|
|
145
|
+
throw new Error("remoteWindow is null");
|
|
146
|
+
}
|
|
147
|
+
return target.contentWindow;
|
|
148
|
+
}
|
|
149
|
+
return target;
|
|
150
|
+
};
|
|
151
|
+
var defineBridge = (name, methods) => {
|
|
152
|
+
return async (target, allowedOrigins = ["*"]) => {
|
|
153
|
+
const remoteWindow = resolveRemoteWindow(target);
|
|
154
|
+
let remotePromise;
|
|
155
|
+
const callbacks = createCallbackBridge(() => remotePromise);
|
|
156
|
+
const bridgeMethods = Object.keys(methods).reduce((wrapped, methodName) => {
|
|
157
|
+
if (methodName === callbackInvokeMethod) {
|
|
158
|
+
throw new Error(`Method name "${callbackInvokeMethod}" is reserved by iframe-bridge-kit`);
|
|
159
|
+
}
|
|
160
|
+
wrapped[methodName] = async (...args) => {
|
|
161
|
+
const result = await methods[methodName].apply(methods, callbacks.deserialize(args));
|
|
162
|
+
return callbacks.serialize(result);
|
|
163
|
+
};
|
|
164
|
+
return wrapped;
|
|
165
|
+
}, {
|
|
166
|
+
[callbackInvokeMethod]: callbacks.invokeLocalCallback
|
|
167
|
+
});
|
|
168
|
+
const conn = (0, import_penpal.connect)({
|
|
169
|
+
messenger: new import_penpal.WindowMessenger({
|
|
170
|
+
remoteWindow,
|
|
171
|
+
allowedOrigins
|
|
172
|
+
}),
|
|
173
|
+
channel: "iframe-bridge-channel",
|
|
174
|
+
methods: bridgeMethods
|
|
175
|
+
});
|
|
176
|
+
remotePromise = conn.promise;
|
|
177
|
+
const remote = await remotePromise;
|
|
178
|
+
return {
|
|
179
|
+
emit(type, data) {
|
|
180
|
+
return remote.onMessage(type, callbacks.serialize(data));
|
|
181
|
+
},
|
|
182
|
+
destroy() {
|
|
183
|
+
callbacks.clearCallbacks();
|
|
184
|
+
conn.destroy();
|
|
185
|
+
}
|
|
186
|
+
};
|
|
48
187
|
};
|
|
49
188
|
};
|
|
50
189
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.mjs
CHANGED
|
@@ -1,26 +1,165 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { WindowMessenger, connect } from "penpal";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
|
|
4
|
+
// src/callbacks.ts
|
|
5
|
+
var callbackRefType = "iframe-bridge-kit.callback";
|
|
6
|
+
var callbackInvokeMethod = "__iframeBridgeInvokeCallback";
|
|
7
|
+
var isObject = (value) => typeof value === "object" && value !== null;
|
|
8
|
+
var isPlainObject = (value) => {
|
|
9
|
+
const proto = Object.getPrototypeOf(value);
|
|
10
|
+
return proto === Object.prototype || proto === null;
|
|
11
|
+
};
|
|
12
|
+
var isCallbackDescriptor = (value) => {
|
|
13
|
+
return isObject(value) && value.__iframeBridgeType === callbackRefType && typeof value.id === "string";
|
|
14
|
+
};
|
|
15
|
+
var createCallbackBridge = (getRemote) => {
|
|
16
|
+
const localCallbacks = /* @__PURE__ */ new Map();
|
|
17
|
+
const localCallbackIds = /* @__PURE__ */ new WeakMap();
|
|
18
|
+
const remoteCallbacks = /* @__PURE__ */ new Map();
|
|
19
|
+
let nextCallbackId = 0;
|
|
20
|
+
const registerLocalCallback = (fn) => {
|
|
21
|
+
let id = localCallbackIds.get(fn);
|
|
22
|
+
if (!id) {
|
|
23
|
+
id = `${Date.now().toString(36)}-${(++nextCallbackId).toString(36)}`;
|
|
24
|
+
localCallbackIds.set(fn, id);
|
|
25
|
+
}
|
|
26
|
+
localCallbacks.set(id, fn);
|
|
27
|
+
return {
|
|
28
|
+
__iframeBridgeType: callbackRefType,
|
|
29
|
+
id
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const serialize = (value, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
33
|
+
if (typeof value === "function") {
|
|
34
|
+
return registerLocalCallback(value);
|
|
35
|
+
}
|
|
36
|
+
if (!isObject(value)) {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
if (seen.has(value)) {
|
|
40
|
+
return seen.get(value);
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
const copy2 = [];
|
|
44
|
+
seen.set(value, copy2);
|
|
45
|
+
value.forEach((item, index) => {
|
|
46
|
+
copy2[index] = serialize(item, seen);
|
|
47
|
+
});
|
|
48
|
+
return copy2;
|
|
49
|
+
}
|
|
50
|
+
if (!isPlainObject(value)) {
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
const copy = {};
|
|
54
|
+
seen.set(value, copy);
|
|
55
|
+
Object.keys(value).forEach((key) => {
|
|
56
|
+
copy[key] = serialize(value[key], seen);
|
|
57
|
+
});
|
|
58
|
+
return copy;
|
|
59
|
+
};
|
|
60
|
+
const deserialize = (value, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
61
|
+
if (!isObject(value)) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
if (isCallbackDescriptor(value)) {
|
|
65
|
+
let callback = remoteCallbacks.get(value.id);
|
|
66
|
+
if (!callback) {
|
|
67
|
+
callback = async (...args) => {
|
|
68
|
+
const remote = await getRemote();
|
|
69
|
+
const result = await remote[callbackInvokeMethod](value.id, serialize(args));
|
|
70
|
+
return deserialize(result);
|
|
71
|
+
};
|
|
72
|
+
remoteCallbacks.set(value.id, callback);
|
|
8
73
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
74
|
+
return callback;
|
|
75
|
+
}
|
|
76
|
+
if (seen.has(value)) {
|
|
77
|
+
return seen.get(value);
|
|
78
|
+
}
|
|
79
|
+
if (Array.isArray(value)) {
|
|
80
|
+
const copy2 = [];
|
|
81
|
+
seen.set(value, copy2);
|
|
82
|
+
value.forEach((item, index) => {
|
|
83
|
+
copy2[index] = deserialize(item, seen);
|
|
16
84
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
85
|
+
return copy2;
|
|
86
|
+
}
|
|
87
|
+
if (!isPlainObject(value)) {
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
const copy = {};
|
|
91
|
+
seen.set(value, copy);
|
|
92
|
+
Object.keys(value).forEach((key) => {
|
|
93
|
+
copy[key] = deserialize(value[key], seen);
|
|
94
|
+
});
|
|
95
|
+
return copy;
|
|
96
|
+
};
|
|
97
|
+
const invokeLocalCallback = async (id, args) => {
|
|
98
|
+
const callback = localCallbacks.get(id);
|
|
99
|
+
if (!callback) {
|
|
100
|
+
throw new Error(`Callback "${id}" is not available`);
|
|
101
|
+
}
|
|
102
|
+
const result = await callback(...deserialize(args));
|
|
103
|
+
return serialize(result);
|
|
104
|
+
};
|
|
105
|
+
const clearCallbacks = () => {
|
|
106
|
+
localCallbacks.clear();
|
|
107
|
+
remoteCallbacks.clear();
|
|
108
|
+
};
|
|
109
|
+
return {
|
|
110
|
+
serialize,
|
|
111
|
+
deserialize,
|
|
112
|
+
invokeLocalCallback,
|
|
113
|
+
clearCallbacks
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// src/index.ts
|
|
118
|
+
var resolveRemoteWindow = (target) => {
|
|
119
|
+
if (typeof HTMLIFrameElement !== "undefined" && target instanceof HTMLIFrameElement) {
|
|
120
|
+
if (!target.contentWindow) {
|
|
121
|
+
throw new Error("remoteWindow is null");
|
|
23
122
|
}
|
|
123
|
+
return target.contentWindow;
|
|
124
|
+
}
|
|
125
|
+
return target;
|
|
126
|
+
};
|
|
127
|
+
var defineBridge = (name, methods) => {
|
|
128
|
+
return async (target, allowedOrigins = ["*"]) => {
|
|
129
|
+
const remoteWindow = resolveRemoteWindow(target);
|
|
130
|
+
let remotePromise;
|
|
131
|
+
const callbacks = createCallbackBridge(() => remotePromise);
|
|
132
|
+
const bridgeMethods = Object.keys(methods).reduce((wrapped, methodName) => {
|
|
133
|
+
if (methodName === callbackInvokeMethod) {
|
|
134
|
+
throw new Error(`Method name "${callbackInvokeMethod}" is reserved by iframe-bridge-kit`);
|
|
135
|
+
}
|
|
136
|
+
wrapped[methodName] = async (...args) => {
|
|
137
|
+
const result = await methods[methodName].apply(methods, callbacks.deserialize(args));
|
|
138
|
+
return callbacks.serialize(result);
|
|
139
|
+
};
|
|
140
|
+
return wrapped;
|
|
141
|
+
}, {
|
|
142
|
+
[callbackInvokeMethod]: callbacks.invokeLocalCallback
|
|
143
|
+
});
|
|
144
|
+
const conn = connect({
|
|
145
|
+
messenger: new WindowMessenger({
|
|
146
|
+
remoteWindow,
|
|
147
|
+
allowedOrigins
|
|
148
|
+
}),
|
|
149
|
+
channel: "iframe-bridge-channel",
|
|
150
|
+
methods: bridgeMethods
|
|
151
|
+
});
|
|
152
|
+
remotePromise = conn.promise;
|
|
153
|
+
const remote = await remotePromise;
|
|
154
|
+
return {
|
|
155
|
+
emit(type, data) {
|
|
156
|
+
return remote.onMessage(type, callbacks.serialize(data));
|
|
157
|
+
},
|
|
158
|
+
destroy() {
|
|
159
|
+
callbacks.clearCallbacks();
|
|
160
|
+
conn.destroy();
|
|
161
|
+
}
|
|
162
|
+
};
|
|
24
163
|
};
|
|
25
164
|
};
|
|
26
165
|
export {
|
package/dist/mini/core.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var m=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var E=(o,t)=>{for(var n in t)m(o,n,{get:t[n],enumerable:!0})},F=(o,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of x(t))!B.call(o,a)&&a!==n&&m(o,a,{get:()=>t[a],enumerable:!(i=_(t,a))||i.enumerable});return o};var A=o=>F(m({},"__esModule",{value:!0}),o);var T={};E(T,{createBridgeClient:()=>I,default:()=>W});module.exports=A(T);var h=require("penpal");var C="iframe-bridge-kit.callback",b="__iframeBridgeInvokeCallback",p=o=>typeof o=="object"&&o!==null,u=o=>{let t=Object.getPrototypeOf(o);return t===Object.prototype||t===null},j=o=>p(o)&&o.__iframeBridgeType===C&&typeof o.id=="string",R=o=>{let t=new Map,n=new WeakMap,i=new Map,a=0,d=e=>{let r=n.get(e);return r||(r=`${Date.now().toString(36)}-${(++a).toString(36)}`,n.set(e,r)),t.set(r,e),{__iframeBridgeType:C,id:r}},c=(e,r=new WeakMap)=>{if(typeof e=="function")return d(e);if(!p(e))return e;if(r.has(e))return r.get(e);if(Array.isArray(e)){let s=[];return r.set(e,s),e.forEach((g,y)=>{s[y]=c(g,r)}),s}if(!u(e))return e;let l={};return r.set(e,l),Object.keys(e).forEach(s=>{l[s]=c(e[s],r)}),l},f=(e,r=new WeakMap)=>{if(!p(e))return e;if(j(e)){let s=i.get(e.id);return s||(s=async(...g)=>{let P=await(await o())[b](e.id,c(g));return f(P)},i.set(e.id,s)),s}if(r.has(e))return r.get(e);if(Array.isArray(e)){let s=[];return r.set(e,s),e.forEach((g,y)=>{s[y]=f(g,r)}),s}if(!u(e))return e;let l={};return r.set(e,l),Object.keys(e).forEach(s=>{l[s]=f(e[s],r)}),l};return{serialize:c,deserialize:f,invokeLocalCallback:async(e,r)=>{let l=t.get(e);if(!l)throw new Error(`Callback "${e}" is not available`);let s=await l(...f(r));return c(s)},clearCallbacks:()=>{t.clear(),i.clear()}}};var O="iframe-bridge-channel",M=["__AllowedOrigins__"],w=class{msgProxy=new Map;initCallbacks=new Set;conn;remotePromise;inited=!1;connectionId=0;callbacks=R(()=>this.getRemote());api;constructor(){let t={onMessage:this.onMessage,offMessage:this.offMessage,isInit:this.isInit,onInit:this.onInit,destroy:this.destroy};this.api=new Proxy({},{get:(n,i)=>{if(i!=="then"&&typeof i=="string")return i in t?t[i]:async(...a)=>{let c=(await this.getRemote())[i];if(typeof c!="function")throw new Error(`Remote method "${String(i)}" is not available`);return this.callbacks.deserialize(await c(...this.callbacks.serialize(a)))}}})}connect=(t,n=M)=>{this.conn?.destroy(),this.inited=!1;let i=++this.connectionId;return this.conn=(0,h.connect)({messenger:new h.WindowMessenger({remoteWindow:t,allowedOrigins:n}),channel:O,methods:{onMessage:this.receiveMessage,[b]:this.callbacks.invokeLocalCallback}}),this.remotePromise=this.conn.promise.then(a=>(i===this.connectionId&&(this.inited=!0,this.notifyInit()),a)),this.remotePromise};getRemote=()=>{if(!this.remotePromise){if(typeof window>"u"||window.parent===window)throw new Error("remoteWindow is not configured. Pass a Window when creating the bridge client.");return this.connect(window.parent)}return this.remotePromise};receiveMessage=(t,n)=>{let i=this.msgProxy.get(t);if(i){let a=this.callbacks.deserialize(n);return i.forEach(d=>d(a)),!0}};notifyInit=()=>{let t=Array.from(this.initCallbacks);this.initCallbacks.clear(),t.forEach(n=>n(this.api))};onMessage=(t,n,i)=>{let a=i?(c=>{n(c),this.offMessage(t,a)}):n,d=this.msgProxy.get(t);return d?d.add(a):this.msgProxy.set(t,new Set([a])),()=>this.offMessage(t,a)};offMessage=(t,n)=>{if(!n){this.msgProxy.delete(t);return}let i=this.msgProxy.get(t);i&&i.delete(n)};isInit=()=>this.inited;onInit=t=>{if(this.inited){t(this.api);return}this.initCallbacks.add(t)};destroy=()=>{this.connectionId++,this.conn?.destroy(),this.conn=void 0,this.remotePromise=void 0,this.inited=!1,this.initCallbacks.clear(),this.callbacks.clearCallbacks()}},I=(o,t=M)=>{let n=new w;return n.connect(o,t),n.api},k,W=()=>(k||(k=I(window.parent)),k);0&&(module.exports={createBridgeClient});
|
package/dist/mini/core.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{WindowMessenger as
|
|
1
|
+
import{WindowMessenger as I,connect as P}from"penpal";var w="iframe-bridge-kit.callback",m="__iframeBridgeInvokeCallback",h=s=>typeof s=="object"&&s!==null,k=s=>{let e=Object.getPrototypeOf(s);return e===Object.prototype||e===null},M=s=>h(s)&&s.__iframeBridgeType===w&&typeof s.id=="string",u=s=>{let e=new Map,r=new WeakMap,i=new Map,a=0,d=t=>{let n=r.get(t);return n||(n=`${Date.now().toString(36)}-${(++a).toString(36)}`,r.set(t,n)),e.set(n,t),{__iframeBridgeType:w,id:n}},c=(t,n=new WeakMap)=>{if(typeof t=="function")return d(t);if(!h(t))return t;if(n.has(t))return n.get(t);if(Array.isArray(t)){let o=[];return n.set(t,o),t.forEach((g,y)=>{o[y]=c(g,n)}),o}if(!k(t))return t;let l={};return n.set(t,l),Object.keys(t).forEach(o=>{l[o]=c(t[o],n)}),l},f=(t,n=new WeakMap)=>{if(!h(t))return t;if(M(t)){let o=i.get(t.id);return o||(o=async(...g)=>{let R=await(await s())[m](t.id,c(g));return f(R)},i.set(t.id,o)),o}if(n.has(t))return n.get(t);if(Array.isArray(t)){let o=[];return n.set(t,o),t.forEach((g,y)=>{o[y]=f(g,n)}),o}if(!k(t))return t;let l={};return n.set(t,l),Object.keys(t).forEach(o=>{l[o]=f(t[o],n)}),l};return{serialize:c,deserialize:f,invokeLocalCallback:async(t,n)=>{let l=e.get(t);if(!l)throw new Error(`Callback "${t}" is not available`);let o=await l(...f(n));return c(o)},clearCallbacks:()=>{e.clear(),i.clear()}}};var _="iframe-bridge-channel",C=["__AllowedOrigins__"],b=class{msgProxy=new Map;initCallbacks=new Set;conn;remotePromise;inited=!1;connectionId=0;callbacks=u(()=>this.getRemote());api;constructor(){let e={onMessage:this.onMessage,offMessage:this.offMessage,isInit:this.isInit,onInit:this.onInit,destroy:this.destroy};this.api=new Proxy({},{get:(r,i)=>{if(i!=="then"&&typeof i=="string")return i in e?e[i]:async(...a)=>{let c=(await this.getRemote())[i];if(typeof c!="function")throw new Error(`Remote method "${String(i)}" is not available`);return this.callbacks.deserialize(await c(...this.callbacks.serialize(a)))}}})}connect=(e,r=C)=>{this.conn?.destroy(),this.inited=!1;let i=++this.connectionId;return this.conn=P({messenger:new I({remoteWindow:e,allowedOrigins:r}),channel:_,methods:{onMessage:this.receiveMessage,[m]:this.callbacks.invokeLocalCallback}}),this.remotePromise=this.conn.promise.then(a=>(i===this.connectionId&&(this.inited=!0,this.notifyInit()),a)),this.remotePromise};getRemote=()=>{if(!this.remotePromise){if(typeof window>"u"||window.parent===window)throw new Error("remoteWindow is not configured. Pass a Window when creating the bridge client.");return this.connect(window.parent)}return this.remotePromise};receiveMessage=(e,r)=>{let i=this.msgProxy.get(e);if(i){let a=this.callbacks.deserialize(r);return i.forEach(d=>d(a)),!0}};notifyInit=()=>{let e=Array.from(this.initCallbacks);this.initCallbacks.clear(),e.forEach(r=>r(this.api))};onMessage=(e,r,i)=>{let a=i?(c=>{r(c),this.offMessage(e,a)}):r,d=this.msgProxy.get(e);return d?d.add(a):this.msgProxy.set(e,new Set([a])),()=>this.offMessage(e,a)};offMessage=(e,r)=>{if(!r){this.msgProxy.delete(e);return}let i=this.msgProxy.get(e);i&&i.delete(r)};isInit=()=>this.inited;onInit=e=>{if(this.inited){e(this.api);return}this.initCallbacks.add(e)};destroy=()=>{this.connectionId++,this.conn?.destroy(),this.conn=void 0,this.remotePromise=void 0,this.inited=!1,this.initCallbacks.clear(),this.callbacks.clearCallbacks()}},x=(s,e=C)=>{let r=new b;return r.connect(s,e),r.api},p,O=()=>(p||(p=x(window.parent)),p);export{x as createBridgeClient,O as default};
|
package/dist/vite.js
CHANGED
|
@@ -36,11 +36,12 @@ module.exports = __toCommonJS(vite_exports);
|
|
|
36
36
|
var ts = __toESM(require("typescript"));
|
|
37
37
|
var path = __toESM(require("path"));
|
|
38
38
|
var fs = __toESM(require("fs"));
|
|
39
|
+
var import_module = require("module");
|
|
39
40
|
|
|
40
41
|
// package.json
|
|
41
42
|
var package_default = {
|
|
42
43
|
name: "iframe-bridge-kit",
|
|
43
|
-
version: "1.
|
|
44
|
+
version: "1.1.1",
|
|
44
45
|
description: "A type-safe communication bridge for iframes. Define strongly typed RPC APIs for cross-window messaging with ease.",
|
|
45
46
|
main: "dist/index.js",
|
|
46
47
|
module: "dist/index.mjs",
|
|
@@ -100,6 +101,20 @@ var package_default = {
|
|
|
100
101
|
|
|
101
102
|
// src/vite.ts
|
|
102
103
|
var packageName = package_default.name;
|
|
104
|
+
var requireFromCwd = (0, import_module.createRequire)(path.join(process.cwd(), "package.json"));
|
|
105
|
+
function getCoreDirs(variant) {
|
|
106
|
+
const dirs = [];
|
|
107
|
+
try {
|
|
108
|
+
const viteEntry = requireFromCwd.resolve(`${packageName}/vite`);
|
|
109
|
+
dirs.push(path.join(path.dirname(viteEntry), variant));
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
dirs.push(
|
|
113
|
+
path.resolve(process.cwd(), "node_modules", packageName, "dist", variant),
|
|
114
|
+
path.resolve(process.cwd(), "dist", variant)
|
|
115
|
+
);
|
|
116
|
+
return Array.from(new Set(dirs));
|
|
117
|
+
}
|
|
103
118
|
function extractScriptFromVue(code) {
|
|
104
119
|
const scriptRegex = /<script(?:\s+setup)?(?:\s+lang\s*=\s*["']?(ts|typescript)["']?)?[^>]*>([\s\S]*?)<\/script>/i;
|
|
105
120
|
const match = code.match(scriptRegex);
|
|
@@ -561,18 +576,10 @@ function generateDtsContent(info, outDir, preserveModules = []) {
|
|
|
561
576
|
});
|
|
562
577
|
lines.push("}");
|
|
563
578
|
lines.push("");
|
|
564
|
-
lines.push("export declare function onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
|
|
565
|
-
lines.push("export declare function onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
566
|
-
lines.push("export declare function offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
|
|
567
|
-
lines.push("export declare function offMessage(type: string, fn?: Function): void;");
|
|
568
|
-
} else {
|
|
569
|
-
lines.push("export declare function onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
570
|
-
lines.push("export declare function offMessage(type: string, fn?: Function): void;");
|
|
571
579
|
}
|
|
572
|
-
lines.push("export declare function
|
|
573
|
-
lines.push("export declare function onInit(cb: Function): void;");
|
|
580
|
+
lines.push("export declare function createBridgeClient(remoteWindow: Window, allowedOrigins?: string[]): BridgeClient;");
|
|
574
581
|
lines.push("");
|
|
575
|
-
lines.push(`export
|
|
582
|
+
lines.push(`export interface BridgeApi {`);
|
|
576
583
|
lines.push(
|
|
577
584
|
...processedMethods.map(
|
|
578
585
|
(m) => (m.jsdoc ? ` ${m.jsdoc}
|
|
@@ -581,6 +588,24 @@ function generateDtsContent(info, outDir, preserveModules = []) {
|
|
|
581
588
|
);
|
|
582
589
|
lines.push("}");
|
|
583
590
|
lines.push("");
|
|
591
|
+
lines.push("export type BridgeClient = BridgeApi & {");
|
|
592
|
+
if (processedEmitTypes.length > 0) {
|
|
593
|
+
lines.push(" onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
|
|
594
|
+
lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
595
|
+
lines.push(" offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
|
|
596
|
+
lines.push(" offMessage(type: string, fn?: Function): void;");
|
|
597
|
+
} else {
|
|
598
|
+
lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
599
|
+
lines.push(" offMessage(type: string, fn?: Function): void;");
|
|
600
|
+
}
|
|
601
|
+
lines.push(" isInit(): boolean;");
|
|
602
|
+
lines.push(" onInit(cb: (api: BridgeClient) => void): void;");
|
|
603
|
+
lines.push(" destroy(): void;");
|
|
604
|
+
lines.push("}");
|
|
605
|
+
lines.push("");
|
|
606
|
+
lines.push("declare const createBridge: () => BridgeClient;");
|
|
607
|
+
lines.push("export default createBridge;");
|
|
608
|
+
lines.push("");
|
|
584
609
|
return lines.join("\n");
|
|
585
610
|
}
|
|
586
611
|
function writeDtsFile(info, options) {
|
|
@@ -620,14 +645,8 @@ function writeBridgeRuntime(bridgeName, options) {
|
|
|
620
645
|
const allowedOrigins = options.allowedOrigins || ["*"];
|
|
621
646
|
const outDir = options.outDir || "bridges";
|
|
622
647
|
const variant = isFull ? "full" : "mini";
|
|
623
|
-
const basePaths = [
|
|
624
|
-
// 1. 假设我们在 dist 目录中运行
|
|
625
|
-
path.resolve(__dirname, variant),
|
|
626
|
-
// 2. 假设我们在 src 目录中运行
|
|
627
|
-
path.resolve(__dirname, "../dist", variant)
|
|
628
|
-
];
|
|
629
648
|
let coreDir = "";
|
|
630
|
-
for (const p of
|
|
649
|
+
for (const p of getCoreDirs(variant)) {
|
|
631
650
|
if (fs.existsSync(p)) {
|
|
632
651
|
coreDir = p;
|
|
633
652
|
break;
|
package/dist/vite.mjs
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
import * as ts from "typescript";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import * as fs from "fs";
|
|
5
|
+
import { createRequire } from "module";
|
|
5
6
|
|
|
6
7
|
// package.json
|
|
7
8
|
var package_default = {
|
|
8
9
|
name: "iframe-bridge-kit",
|
|
9
|
-
version: "1.
|
|
10
|
+
version: "1.1.1",
|
|
10
11
|
description: "A type-safe communication bridge for iframes. Define strongly typed RPC APIs for cross-window messaging with ease.",
|
|
11
12
|
main: "dist/index.js",
|
|
12
13
|
module: "dist/index.mjs",
|
|
@@ -66,6 +67,20 @@ var package_default = {
|
|
|
66
67
|
|
|
67
68
|
// src/vite.ts
|
|
68
69
|
var packageName = package_default.name;
|
|
70
|
+
var requireFromCwd = createRequire(path.join(process.cwd(), "package.json"));
|
|
71
|
+
function getCoreDirs(variant) {
|
|
72
|
+
const dirs = [];
|
|
73
|
+
try {
|
|
74
|
+
const viteEntry = requireFromCwd.resolve(`${packageName}/vite`);
|
|
75
|
+
dirs.push(path.join(path.dirname(viteEntry), variant));
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
dirs.push(
|
|
79
|
+
path.resolve(process.cwd(), "node_modules", packageName, "dist", variant),
|
|
80
|
+
path.resolve(process.cwd(), "dist", variant)
|
|
81
|
+
);
|
|
82
|
+
return Array.from(new Set(dirs));
|
|
83
|
+
}
|
|
69
84
|
function extractScriptFromVue(code) {
|
|
70
85
|
const scriptRegex = /<script(?:\s+setup)?(?:\s+lang\s*=\s*["']?(ts|typescript)["']?)?[^>]*>([\s\S]*?)<\/script>/i;
|
|
71
86
|
const match = code.match(scriptRegex);
|
|
@@ -527,18 +542,10 @@ function generateDtsContent(info, outDir, preserveModules = []) {
|
|
|
527
542
|
});
|
|
528
543
|
lines.push("}");
|
|
529
544
|
lines.push("");
|
|
530
|
-
lines.push("export declare function onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
|
|
531
|
-
lines.push("export declare function onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
532
|
-
lines.push("export declare function offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
|
|
533
|
-
lines.push("export declare function offMessage(type: string, fn?: Function): void;");
|
|
534
|
-
} else {
|
|
535
|
-
lines.push("export declare function onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
536
|
-
lines.push("export declare function offMessage(type: string, fn?: Function): void;");
|
|
537
545
|
}
|
|
538
|
-
lines.push("export declare function
|
|
539
|
-
lines.push("export declare function onInit(cb: Function): void;");
|
|
546
|
+
lines.push("export declare function createBridgeClient(remoteWindow: Window, allowedOrigins?: string[]): BridgeClient;");
|
|
540
547
|
lines.push("");
|
|
541
|
-
lines.push(`export
|
|
548
|
+
lines.push(`export interface BridgeApi {`);
|
|
542
549
|
lines.push(
|
|
543
550
|
...processedMethods.map(
|
|
544
551
|
(m) => (m.jsdoc ? ` ${m.jsdoc}
|
|
@@ -547,6 +554,24 @@ function generateDtsContent(info, outDir, preserveModules = []) {
|
|
|
547
554
|
);
|
|
548
555
|
lines.push("}");
|
|
549
556
|
lines.push("");
|
|
557
|
+
lines.push("export type BridgeClient = BridgeApi & {");
|
|
558
|
+
if (processedEmitTypes.length > 0) {
|
|
559
|
+
lines.push(" onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
|
|
560
|
+
lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
561
|
+
lines.push(" offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
|
|
562
|
+
lines.push(" offMessage(type: string, fn?: Function): void;");
|
|
563
|
+
} else {
|
|
564
|
+
lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
|
|
565
|
+
lines.push(" offMessage(type: string, fn?: Function): void;");
|
|
566
|
+
}
|
|
567
|
+
lines.push(" isInit(): boolean;");
|
|
568
|
+
lines.push(" onInit(cb: (api: BridgeClient) => void): void;");
|
|
569
|
+
lines.push(" destroy(): void;");
|
|
570
|
+
lines.push("}");
|
|
571
|
+
lines.push("");
|
|
572
|
+
lines.push("declare const createBridge: () => BridgeClient;");
|
|
573
|
+
lines.push("export default createBridge;");
|
|
574
|
+
lines.push("");
|
|
550
575
|
return lines.join("\n");
|
|
551
576
|
}
|
|
552
577
|
function writeDtsFile(info, options) {
|
|
@@ -586,14 +611,8 @@ function writeBridgeRuntime(bridgeName, options) {
|
|
|
586
611
|
const allowedOrigins = options.allowedOrigins || ["*"];
|
|
587
612
|
const outDir = options.outDir || "bridges";
|
|
588
613
|
const variant = isFull ? "full" : "mini";
|
|
589
|
-
const basePaths = [
|
|
590
|
-
// 1. 假设我们在 dist 目录中运行
|
|
591
|
-
path.resolve(__dirname, variant),
|
|
592
|
-
// 2. 假设我们在 src 目录中运行
|
|
593
|
-
path.resolve(__dirname, "../dist", variant)
|
|
594
|
-
];
|
|
595
614
|
let coreDir = "";
|
|
596
|
-
for (const p of
|
|
615
|
+
for (const p of getCoreDirs(variant)) {
|
|
597
616
|
if (fs.existsSync(p)) {
|
|
598
617
|
coreDir = p;
|
|
599
618
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iframe-bridge-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "A type-safe communication bridge for iframes. Define strongly typed RPC APIs for cross-window messaging with ease.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|