iframe-bridge-kit 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,257 @@
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 ParentApi, { onMessage, onInit } from '../bridges/app-bridge'
104
-
105
- // Wait for connection initialization (optional)
106
- onInit(() => {
107
- console.log('Bridge connected!')
108
- })
109
-
110
- // 1. Call parent window methods (RPC)
111
- async function fetchUser() {
112
- // ✅ Full type hints for id and return value here!
113
- const user = await ParentApi.getUserInfo('123')
114
- console.log(user.name)
115
- }
116
-
117
- // 2. Listen for parent window messages
118
- // ✅ Type hints for 'theme-change' and callback data
119
- onMessage('theme-change', (data) => {
120
- console.log('New theme:', data.mode)
121
- })
122
- ```
123
-
124
- ## 🧩 Type Support Details
125
-
126
- The core magic of `iframe-bridge-kit` lies in how it handles types.
127
-
128
- When you define methods:
129
-
130
- ```typescript
131
- getUserInfo(id: string): Promise<User>
132
- ```
133
-
134
- 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.
135
-
136
- ### Supported Type Features
137
-
138
- * Basic types (string, number, boolean)
139
- * Interfaces & Type Aliases
140
- * Generic Expansion
141
- * Third-party library types (automatically handles import paths)
142
-
143
- ## 🔌 API Reference
144
-
145
- ### `defineBridge<TEmit>(name, methods)`
146
-
147
- * **name**: `string` - Bridge name, determines the generated directory name.
148
- * **methods**: `Object` - Collection of methods exposed to the child window.
149
- * **TEmit**: `Generic` - (Optional) Defines the event type mapping for messages sent via `emit` from the parent.
150
-
151
- Returns an object containing:
152
-
153
- * `create(iframeEl, allowedOrigins?)`: Initializes the connection and returns an `{ emit }` object.
154
-
155
- ### Vite Plugin Options (`IframeBridgeOptions`)
156
-
157
- | Option | Type | Default | Description |
158
- |:---|:---|:---|:---|
159
- | `outDir` | `string` | `'bridges'` | Output directory for generated code. Recommended `'src/bridges'`. |
160
- | `allowedOrigins` | `string[]` | `['*']` | List of allowed origin domains for communication. |
161
- | `full` | `boolean` | `true` | Whether to generate code containing full dependencies. |
162
- | `preserveModules` | `string[]` | `[]` | Preserve imports for specific modules instead of expanding types (e.g., `['vue']`). |
163
-
164
- ### Generated Child API
165
-
166
- Assuming `outDir` is `src/bridges` and the bridge name is `my-bridge`, you can import from `src/bridges/my-bridge`:
167
-
168
- * **`default` (ParentApi)**: A proxy object containing all parent methods. All methods return a `Promise`.
169
- * **`onMessage(type, callback, once?)`**: Listen for events sent by the parent.
170
- * **`offMessage(type, callback?)`**: Remove an event listener.
171
- * **`onInit(callback)`**: Triggered when the connection is successfully established.
172
- * **`isInit()`**: Returns the current connection status.
173
-
174
- ## ⚠️ Notes
175
-
176
- 1. **Same-Origin Policy**: While Penpal simplifies postMessage, please ensure `allowedOrigins` is correctly configured for security.
177
- 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.
178
- 3. **JSON Serialization**: Data transmitted across windows must be JSON serializable (Functions, DOM nodes, etc., are not supported).
179
-
180
- ## License
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 the parent window and iframe child window to expose RPC methods to each other 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
+ * 🚀 **No Duplicate Type Definitions**: The other window does not need to manually sync interfaces; simply import the generated bridge file to use.
11
+ * 📡 **RPC Style**: Call cross-window methods just like calling `async` functions.
12
+ * ⚡ **Event Mechanism**: Supports strongly-typed broadcast messages from both parent and iframe child windows.
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 Defines APIs, Iframe Calls 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 ParentApi, { onMessage, onInit } from '../bridges/app-bridge'
104
+
105
+ // Wait for connection initialization (optional)
106
+ onInit(() => {
107
+ console.log('Bridge connected!')
108
+ })
109
+
110
+ // 1. Call parent window methods (RPC)
111
+ async function fetchUser() {
112
+ // ✅ Full type hints for id and return value here!
113
+ const user = await ParentApi.getUserInfo('123')
114
+ console.log(user.name)
115
+ }
116
+
117
+ // 2. Listen for parent window messages
118
+ // ✅ Type hints for 'theme-change' and callback data
119
+ onMessage('theme-change', (data) => {
120
+ console.log('New theme:', data.mode)
121
+ })
122
+ ```
123
+
124
+ ### 3\. Iframe Defines APIs, Parent Calls Iframe
125
+
126
+ If your main use case is to build an iframe page first and let the parent window integrate with it, use `defineIframeBridge` inside the iframe project. The plugin will generate a parent-side client from the methods exposed by the iframe.
127
+
128
+ ```typescript
129
+ // src/iframeBridge.ts (inside the iframe project)
130
+ import { defineIframeBridge } from 'iframe-bridge-kit'
131
+
132
+ interface ChildEmitMap {
133
+ 'ready': { url: string }
134
+ 'height-change': { height: number }
135
+ }
136
+
137
+ export const childBridge = defineIframeBridge<ChildEmitMap>('child-app', {
138
+ async getPageInfo() {
139
+ return {
140
+ title: document.title,
141
+ url: location.href
142
+ }
143
+ },
144
+
145
+ setTheme(mode: 'dark' | 'light') {
146
+ document.documentElement.dataset.theme = mode
147
+ return true
148
+ }
149
+ })
150
+
151
+ childBridge.connect().then((parent) => {
152
+ parent.emit('ready', { url: location.href })
153
+ })
154
+ ```
155
+
156
+ After saving, the plugin generates `src/bridges/child-app/`. The parent project can import that directory and call `create(iframe)` to get strongly-typed methods exposed by the iframe.
157
+
158
+ ```typescript
159
+ // src/views/Parent.vue (inside the parent project)
160
+ import ChildBridge from '../bridges/child-app'
161
+
162
+ const iframe = document.querySelector<HTMLIFrameElement>('#child-app')!
163
+ const child = ChildBridge.create(iframe)
164
+
165
+ child.onInit(async () => {
166
+ const info = await child.api.getPageInfo()
167
+ console.log(info.title)
168
+
169
+ await child.api.setTheme('dark')
170
+ })
171
+
172
+ child.onMessage('height-change', ({ height }) => {
173
+ iframe.style.height = `${height}px`
174
+ })
175
+ ```
176
+
177
+ ## 🧩 Type Support Details
178
+
179
+ The core magic of `iframe-bridge-kit` lies in how it handles types.
180
+
181
+ When you define methods:
182
+
183
+ ```typescript
184
+ getUserInfo(id: string): Promise<User>
185
+ ```
186
+
187
+ 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.
188
+
189
+ ### Supported Type Features
190
+
191
+ * Basic types (string, number, boolean)
192
+ * Interfaces & Type Aliases
193
+ * Generic Expansion
194
+ * Third-party library types (automatically handles import paths)
195
+
196
+ ## 🔌 API Reference
197
+
198
+ ### `defineBridge<TEmit>(name, methods)`
199
+
200
+ * **name**: `string` - Bridge name, determines the generated directory name.
201
+ * **methods**: `Object` - Collection of methods exposed to the child window.
202
+ * **TEmit**: `Generic` - (Optional) Defines the event type mapping for messages sent via `emit` from the parent.
203
+
204
+ Returns an object containing:
205
+
206
+ * `create(iframeEl, allowedOrigins?)`: Initializes the connection and returns an `{ emit }` object.
207
+
208
+ ### `defineIframeBridge<TEmit>(name, methods)`
209
+
210
+ * **name**: `string` - Bridge name, determines the generated directory name.
211
+ * **methods**: `Object` - Collection of methods exposed from the iframe to the parent window.
212
+ * **TEmit**: `Generic` - (Optional) Defines the event type mapping for messages sent via `emit` from the iframe.
213
+
214
+ Returns an object containing:
215
+
216
+ * `connect(allowedOrigins?)`: Connects to the parent window from inside the iframe and returns an `{ emit, destroy }` object.
217
+
218
+ ### Vite Plugin Options (`IframeBridgeOptions`)
219
+
220
+ | Option | Type | Default | Description |
221
+ |:---|:---|:---|:---|
222
+ | `outDir` | `string` | `'bridges'` | Output directory for generated code. Recommended `'src/bridges'`. |
223
+ | `allowedOrigins` | `string[]` | `['*']` | List of allowed origin domains for communication. |
224
+ | `full` | `boolean` | `true` | Whether to generate code containing full dependencies. |
225
+ | `preserveModules` | `string[]` | `[]` | Preserve imports for specific modules instead of expanding types (e.g., `['vue']`). |
226
+
227
+ ### Generated Child API
228
+
229
+ Assuming `outDir` is `src/bridges` and the bridge name is `my-bridge`, you can import from `src/bridges/my-bridge`:
230
+
231
+ * **`default` (ParentApi)**: A proxy object containing all parent methods. All methods return a `Promise`.
232
+ * **`onMessage(type, callback, once?)`**: Listen for events sent by the parent.
233
+ * **`offMessage(type, callback?)`**: Remove an event listener.
234
+ * **`onInit(callback)`**: Triggered when the connection is successfully established.
235
+ * **`isInit()`**: Returns the current connection status.
236
+
237
+ ### Generated Parent API
238
+
239
+ When the bridge comes from `defineIframeBridge`, the same generated directory exports a parent-side client:
240
+
241
+ * **`create(iframeEl, allowedOrigins?)`**: Initializes the connection to the iframe and returns a `BridgeConnection`.
242
+ * **`connection.api`**: A strongly-typed proxy for methods exposed by the iframe. All methods return a `Promise`.
243
+ * **`connection.onMessage(type, callback, once?)`**: Listen for events sent by the iframe.
244
+ * **`connection.offMessage(type, callback?)`**: Remove an event listener.
245
+ * **`connection.onInit(callback)`**: Triggered when the connection is successfully established.
246
+ * **`connection.isInit()`**: Returns the current connection status.
247
+ * **`connection.destroy()`**: Disconnects the current connection.
248
+
249
+ ## ⚠️ Notes
250
+
251
+ 1. **Same-Origin Policy**: While Penpal simplifies postMessage, please ensure `allowedOrigins` is correctly configured for security.
252
+ 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.
253
+ 3. **JSON Serialization**: Data transmitted across windows must be JSON serializable (Functions, DOM nodes, etc., are not supported).
254
+
255
+ ## License
256
+
182
257
  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 R=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var Z=Object.prototype.hasOwnProperty;var ee=(e,t)=>{for(var r in t)R(e,r,{get:t[r],enumerable:!0})},te=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Q(t))!Z.call(e,s)&&s!==r&&R(e,s,{get:()=>t[s],enumerable:!(n=B(t,s))||n.enumerable});return e};var re=e=>te(R({},"__esModule",{value:!0}),e);var Fe={};ee(Fe,{default:()=>De,isInit:()=>ke,offMessage:()=>D,onInit:()=>He,onMessage:()=>be});module.exports=re(Fe);var ne=class extends Error{code;constructor(e,t){super(t),this.name="PenpalError",this.code=e}},u=ne,se=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof u?e.code:void 0}),ae=({name:e,message:t,stack:r,penpalCode:n})=>{let s=n?new u(n,t):new Error(t);return s.name=e,s.stack=r,s},oe=Symbol("Reply"),ie=class{value;transferables;#t=oe;constructor(e,t){this.value=e,this.transferables=t?.transferables}},de=ie,p="penpal",C=e=>typeof e=="object"&&e!==null,V=e=>typeof e=="function",le=e=>C(e)&&e.namespace===p,N=e=>e.type==="SYN",L=e=>e.type==="ACK1",T=e=>e.type==="ACK2",W=e=>e.type==="CALL",Y=e=>e.type==="REPLY",ce=e=>e.type==="DESTROY",j=(e,t=[])=>{let r=[];for(let n of Object.keys(e)){let s=e[n];V(s)?r.push([...t,n]):C(s)&&r.push(...j(s,[...t,n]))}return r},he=(e,t)=>{let r=e.reduce((n,s)=>C(n)?n[s]:void 0,t);return V(r)?r:void 0},g=e=>e.join("."),F=(e,t,r)=>({namespace:p,channel:e,type:"REPLY",callId:t,isError:!0,...r instanceof Error?{value:se(r),isSerializedErrorInstance:!0}:{value:r}}),ue=(e,t,r,n)=>{let s=!1,l=async f=>{if(s||!W(f))return;n?.(`Received ${g(f.methodPath)}() call`,f);let{methodPath:v,args:c,id:o}=f,a,M;try{let d=he(v,t);if(!d)throw new u("METHOD_NOT_FOUND",`Method \`${g(v)}\` is not found.`);let h=await d(...c);h instanceof de&&(M=h.transferables,h=await h.value),a={namespace:p,channel:r,type:"REPLY",callId:o,value:h}}catch(d){a=F(r,o,d)}if(!s)try{n?.(`Sending ${g(v)}() reply`,a),e.sendMessage(a,M)}catch(d){throw d.name==="DataCloneError"&&(a=F(r,o,d),n?.(`Sending ${g(v)}() reply`,a),e.sendMessage(a)),d}};return e.addMessageHandler(l),()=>{s=!0,e.removeMessageHandler(l)}},fe=ue,z=crypto.randomUUID?.bind(crypto)??(()=>new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")),pe=Symbol("CallOptions"),ve=class{transferables;timeout;#t=pe;constructor(e){this.transferables=e?.transferables,this.timeout=e?.timeout}},Me=ve,ge=new Set(["apply","call","bind"]),K=(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):K(e,t,[...r,s])},apply(n,s,l){return e(r,l)}}),x=e=>new u("CONNECTION_DESTROYED",`Method call ${g(e)}() failed due to destroyed connection`),ye=(e,t,r)=>{let n=!1,s=new Map,l=c=>{if(!Y(c))return;let{callId:o,value:a,isError:M,isSerializedErrorInstance:d}=c,h=s.get(o);h&&(s.delete(o),r?.(`Received ${g(h.methodPath)}() call`,c),M?h.reject(d?ae(a):a):h.resolve(a))};return e.addMessageHandler(l),{remoteProxy:K((c,o)=>{if(n)throw x(c);let a=z(),M=o[o.length-1],d=M instanceof Me,{timeout:h,transferables:_}=d?M:{},A=d?o.slice(0,-1):o;return new Promise((S,I)=>{let P=h!==void 0?window.setTimeout(()=>{s.delete(a),I(new u("METHOD_CALL_TIMEOUT",`Method call ${g(c)}() timed out after ${h}ms`))},h):void 0;s.set(a,{methodPath:c,resolve:S,reject:I,timeoutId:P});try{let E={namespace:p,channel:t,type:"CALL",id:a,methodPath:c,args:A};r?.(`Sending ${g(c)}() call`,E),e.sendMessage(E,_)}catch(E){I(new u("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()}}},Ee=ye,Ie=()=>{let e,t;return{promise:new Promise((n,s)=>{e=n,t=s}),resolve:e,reject:t}},we=Ie,O="deprecated-penpal",Ae=e=>C(e)&&"penpal"in e,Se=e=>e.split("."),U=e=>e.join("."),me=e=>{try{return JSON.stringify(e)}catch{return String(e)}},G=e=>new u("TRANSMISSION_FAILED",`Unexpected message to translate: ${me(e)}`),Ne=e=>{if(e.penpal==="syn")return{namespace:p,channel:void 0,type:"SYN",participantId:O};if(e.penpal==="ack")return{namespace:p,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:p,channel:void 0,type:"CALL",id:e.id,methodPath:Se(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:p,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:p,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw G(e)},Ce=e=>{if(L(e))return{penpal:"synAck",methodNames:e.methodPaths.map(U)};if(W(e))return{penpal:"call",id:e.id,methodName:U(e.methodPath),args:e.args};if(Y(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 G(e)},_e=({messenger:e,methods:t,timeout:r,channel:n,log:s})=>{let l=z(),f,v=[],c=!1,o=j(t),{promise:a,resolve:M,reject:d}=we(),h=r!==void 0?setTimeout(()=>{d(new u("CONNECTION_TIMEOUT",`Connection timed out after ${r}ms`))},r):void 0,_=()=>{for(let i of v)i()},A=()=>{if(c)return;v.push(fe(e,t,n,s));let{remoteProxy:i,destroy:y}=Ee(e,n,s);v.push(y),clearTimeout(h),c=!0,M({remoteProxy:i,destroy:_})},S=()=>{let i={namespace:p,type:"SYN",channel:n,participantId:l};s?.("Sending handshake SYN",i);try{e.sendMessage(i)}catch(y){d(new u("TRANSMISSION_FAILED",y.message))}},I=i=>{if(s?.("Received handshake SYN",i),i.participantId===f&&f!==O||(f=i.participantId,S(),!(l>f||f===O)))return;let m={namespace:p,channel:n,type:"ACK1",methodPaths:o};s?.("Sending handshake ACK1",m);try{e.sendMessage(m)}catch(q){d(new u("TRANSMISSION_FAILED",q.message));return}},P=i=>{s?.("Received handshake ACK1",i);let y={namespace:p,channel:n,type:"ACK2"};s?.("Sending handshake ACK2",y);try{e.sendMessage(y)}catch(m){d(new u("TRANSMISSION_FAILED",m.message));return}A()},E=i=>{s?.("Received handshake ACK2",i),A()},H=i=>{N(i)&&I(i),L(i)&&P(i),T(i)&&E(i)};return e.addMessageHandler(H),v.push(()=>e.removeMessageHandler(H)),S(),a},Pe=_e,Re=e=>{let t=!1,r;return(...n)=>(t||(t=!0,r=e(...n)),r)},Te=Re,$=new WeakSet,Oe=({messenger:e,methods:t={},timeout:r,channel:n,log:s})=>{if(!e)throw new u("INVALID_ARGUMENT","messenger must be defined");if($.has(e))throw new u("INVALID_ARGUMENT","A messenger can only be used for a single connection");$.add(e);let l=[e.destroy],f=Te(o=>{if(o){let a={namespace:p,channel:n,type:"DESTROY"};try{e.sendMessage(a)}catch{}}for(let a of l)a();s?.("Connection destroyed")}),v=o=>le(o)&&o.channel===n;return{promise:(async()=>{try{e.initialize({log:s,validateReceivedMessage:v}),e.addMessageHandler(M=>{ce(M)&&f(!1)});let{remoteProxy:o,destroy:a}=await Pe({messenger:e,methods:t,timeout:r,channel:n,log:s});return l.push(a),o}catch(o){throw f(!0),o}})(),destroy:()=>{f(!0)}}},J=Oe,Le=class{#t;#s;#r;#i;#a;#n=new Set;#e;#o=!1;constructor({remoteWindow:e,allowedOrigins:t}){if(!e)throw new u("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.#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.#o){let r=this.#o?Ce(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 u("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.#c(),this.#n.clear()};#u=e=>this.#s.some(t=>t instanceof RegExp?t.test(e):t===e||t==="*");#d=e=>{if(N(e))return"*";if(!this.#a)throw new u("TRANSMISSION_FAILED","Cannot send message because the remote origin is not established");return this.#a==="null"&&this.#s.includes("*")?"*":this.#a};#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){if(Ae(n)){this.#r?.("Please upgrade the child window to the latest version of Penpal."),this.#o=!0;try{n=Ne(n)}catch(s){this.#r?.(`Failed to translate deprecated message: ${s.message}`);return}}if(this.#i?.(n)){if(!this.#u(t)){this.#r?.(`Received a message from origin \`${t}\` which did not match allowed origins \`[${this.#s.join(", ")}]\``);return}if(N(n)&&(this.#c(),this.#a=t),T(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.#l),this.#e.start()}for(let s of this.#n)s(n)}}};#l=({data:e})=>{if(this.#i?.(e))for(let t of this.#n)t(e)}},X=Le;var w=new Map,b=J({messenger:new X({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(e,t){let r=w.get(e);if(r)return r.forEach(n=>n(t)),!0}}}),De=new Proxy({},{get(e,t){return async(...r)=>await b.promise.then(n=>n[t](...r))}}),be=(e,t,r)=>{let n=r?(l=>{t(l),D(e,n)}):t,s=w.get(e);return s?s.add(n):w.set(e,new Set([n])),()=>D(e,n)},D=(e,t)=>{if(!t){w.delete(e);return}let r=w.get(e);r&&r.delete(t)},k=!1;b.promise.then(()=>{k=!0});var ke=()=>k,He=e=>{if(k){e();return}b.promise.then(()=>{e()})};0&&(module.exports={isInit,offMessage,onInit,onMessage});
@@ -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 q=class extends Error{code;constructor(e,t){super(t),this.name="PenpalError",this.code=e}},u=q,B=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof u?e.code:void 0}),Q=({name:e,message:t,stack:r,penpalCode:n})=>{let s=n?new u(n,t):new Error(t);return s.name=e,s.stack=r,s},Z=Symbol("Reply"),ee=class{value;transferables;#t=Z;constructor(e,t){this.value=e,this.transferables=t?.transferables}},te=ee,p="penpal",C=e=>typeof e=="object"&&e!==null,U=e=>typeof e=="function",re=e=>C(e)&&e.namespace===p,N=e=>e.type==="SYN",O=e=>e.type==="ACK1",R=e=>e.type==="ACK2",$=e=>e.type==="CALL",V=e=>e.type==="REPLY",ne=e=>e.type==="DESTROY",W=(e,t=[])=>{let r=[];for(let n of Object.keys(e)){let s=e[n];U(s)?r.push([...t,n]):C(s)&&r.push(...W(s,[...t,n]))}return r},se=(e,t)=>{let r=e.reduce((n,s)=>C(n)?n[s]:void 0,t);return U(r)?r:void 0},g=e=>e.join("."),k=(e,t,r)=>({namespace:p,channel:e,type:"REPLY",callId:t,isError:!0,...r instanceof Error?{value:B(r),isSerializedErrorInstance:!0}:{value:r}}),ae=(e,t,r,n)=>{let s=!1,l=async f=>{if(s||!$(f))return;n?.(`Received ${g(f.methodPath)}() call`,f);let{methodPath:v,args:c,id:o}=f,a,M;try{let d=se(v,t);if(!d)throw new u("METHOD_NOT_FOUND",`Method \`${g(v)}\` is not found.`);let h=await d(...c);h instanceof te&&(M=h.transferables,h=await h.value),a={namespace:p,channel:r,type:"REPLY",callId:o,value:h}}catch(d){a=k(r,o,d)}if(!s)try{n?.(`Sending ${g(v)}() reply`,a),e.sendMessage(a,M)}catch(d){throw d.name==="DataCloneError"&&(a=k(r,o,d),n?.(`Sending ${g(v)}() reply`,a),e.sendMessage(a)),d}};return e.addMessageHandler(l),()=>{s=!0,e.removeMessageHandler(l)}},oe=ae,Y=crypto.randomUUID?.bind(crypto)??(()=>new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")),ie=Symbol("CallOptions"),de=class{transferables;timeout;#t=ie;constructor(e){this.transferables=e?.transferables,this.timeout=e?.timeout}},le=de,ce=new Set(["apply","call","bind"]),j=(e,t,r=[])=>new Proxy(r.length?()=>{}:Object.create(null),{get(n,s){if(s!=="then")return r.length&&ce.has(s)?Reflect.get(n,s):j(e,t,[...r,s])},apply(n,s,l){return e(r,l)}}),H=e=>new u("CONNECTION_DESTROYED",`Method call ${g(e)}() failed due to destroyed connection`),he=(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 ${g(h.methodPath)}() call`,c),M?h.reject(d?Q(a):a):h.resolve(a))};return e.addMessageHandler(l),{remoteProxy:j((c,o)=>{if(n)throw H(c);let a=Y(),M=o[o.length-1],d=M instanceof le,{timeout:h,transferables:_}=d?M:{},A=d?o.slice(0,-1):o;return new Promise((S,I)=>{let P=h!==void 0?window.setTimeout(()=>{s.delete(a),I(new u("METHOD_CALL_TIMEOUT",`Method call ${g(c)}() timed out after ${h}ms`))},h):void 0;s.set(a,{methodPath:c,resolve:S,reject:I,timeoutId:P});try{let E={namespace:p,channel:t,type:"CALL",id:a,methodPath:c,args:A};r?.(`Sending ${g(c)}() call`,E),e.sendMessage(E,_)}catch(E){I(new u("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(H(c));s.clear()}}},ue=he,fe=()=>{let e,t;return{promise:new Promise((n,s)=>{e=n,t=s}),resolve:e,reject:t}},pe=fe,T="deprecated-penpal",ve=e=>C(e)&&"penpal"in e,Me=e=>e.split("."),F=e=>e.join("."),ge=e=>{try{return JSON.stringify(e)}catch{return String(e)}},z=e=>new u("TRANSMISSION_FAILED",`Unexpected message to translate: ${ge(e)}`),ye=e=>{if(e.penpal==="syn")return{namespace:p,channel:void 0,type:"SYN",participantId:T};if(e.penpal==="ack")return{namespace:p,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:p,channel:void 0,type:"CALL",id:e.id,methodPath:Me(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:p,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:p,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw z(e)},Ee=e=>{if(O(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 z(e)},Ie=({messenger:e,methods:t,timeout:r,channel:n,log:s})=>{let l=Y(),f,v=[],c=!1,o=W(t),{promise:a,resolve:M,reject:d}=pe(),h=r!==void 0?setTimeout(()=>{d(new u("CONNECTION_TIMEOUT",`Connection timed out after ${r}ms`))},r):void 0,_=()=>{for(let i of v)i()},A=()=>{if(c)return;v.push(oe(e,t,n,s));let{remoteProxy:i,destroy:y}=ue(e,n,s);v.push(y),clearTimeout(h),c=!0,M({remoteProxy:i,destroy:_})},S=()=>{let i={namespace:p,type:"SYN",channel:n,participantId:l};s?.("Sending handshake SYN",i);try{e.sendMessage(i)}catch(y){d(new u("TRANSMISSION_FAILED",y.message))}},I=i=>{if(s?.("Received handshake SYN",i),i.participantId===f&&f!==T||(f=i.participantId,S(),!(l>f||f===T)))return;let m={namespace:p,channel:n,type:"ACK1",methodPaths:o};s?.("Sending handshake ACK1",m);try{e.sendMessage(m)}catch(X){d(new u("TRANSMISSION_FAILED",X.message));return}},P=i=>{s?.("Received handshake ACK1",i);let y={namespace:p,channel:n,type:"ACK2"};s?.("Sending handshake ACK2",y);try{e.sendMessage(y)}catch(m){d(new u("TRANSMISSION_FAILED",m.message));return}A()},E=i=>{s?.("Received handshake ACK2",i),A()},b=i=>{N(i)&&I(i),O(i)&&P(i),R(i)&&E(i)};return e.addMessageHandler(b),v.push(()=>e.removeMessageHandler(b)),S(),a},we=Ie,Ae=e=>{let t=!1,r;return(...n)=>(t||(t=!0,r=e(...n)),r)},Se=Ae,x=new WeakSet,me=({messenger:e,methods:t={},timeout:r,channel:n,log:s})=>{if(!e)throw new u("INVALID_ARGUMENT","messenger must be defined");if(x.has(e))throw new u("INVALID_ARGUMENT","A messenger can only be used for a single connection");x.add(e);let l=[e.destroy],f=Se(o=>{if(o){let a={namespace:p,channel:n,type:"DESTROY"};try{e.sendMessage(a)}catch{}}for(let a of l)a();s?.("Connection destroyed")}),v=o=>re(o)&&o.channel===n;return{promise:(async()=>{try{e.initialize({log:s,validateReceivedMessage:v}),e.addMessageHandler(M=>{ne(M)&&f(!1)});let{remoteProxy:o,destroy:a}=await we({messenger:e,methods:t,timeout:r,channel:n,log:s});return l.push(a),o}catch(o){throw f(!0),o}})(),destroy:()=>{f(!0)}}},K=me,Ne=class{#t;#s;#r;#i;#a;#n=new Set;#e;#o=!1;constructor({remoteWindow:e,allowedOrigins:t}){if(!e)throw new u("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.#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(O(e)||this.#o){let r=this.#o?Ee(e):e,n=this.#d(e);this.#t.postMessage(r,{targetOrigin:n,transfer:t});return}if(R(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 u("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.#c(),this.#n.clear()};#u=e=>this.#s.some(t=>t instanceof RegExp?t.test(e):t===e||t==="*");#d=e=>{if(N(e))return"*";if(!this.#a)throw new u("TRANSMISSION_FAILED","Cannot send message because the remote origin is not established");return this.#a==="null"&&this.#s.includes("*")?"*":this.#a};#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){if(ve(n)){this.#r?.("Please upgrade the child window to the latest version of Penpal."),this.#o=!0;try{n=ye(n)}catch(s){this.#r?.(`Failed to translate deprecated message: ${s.message}`);return}}if(this.#i?.(n)){if(!this.#u(t)){this.#r?.(`Received a message from origin \`${t}\` which did not match allowed origins \`[${this.#s.join(", ")}]\``);return}if(N(n)&&(this.#c(),this.#a=t),R(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.#l),this.#e.start()}for(let s of this.#n)s(n)}}};#l=({data:e})=>{if(this.#i?.(e))for(let t of this.#n)t(e)}},G=Ne;var w=new Map,L=K({messenger:new G({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(e,t){let r=w.get(e);if(r)return r.forEach(n=>n(t)),!0}}}),Le=new Proxy({},{get(e,t){return async(...r)=>await L.promise.then(n=>n[t](...r))}}),De=(e,t,r)=>{let n=r?(l=>{t(l),J(e,n)}):t,s=w.get(e);return s?s.add(n):w.set(e,new Set([n])),()=>J(e,n)},J=(e,t)=>{if(!t){w.delete(e);return}let r=w.get(e);r&&r.delete(t)},D=!1;L.promise.then(()=>{D=!0});var be=()=>D,ke=e=>{if(D){e();return}L.promise.then(()=>{e()})};export{Le as default,be as isInit,J as offMessage,ke as onInit,De as onMessage};
@@ -0,0 +1 @@
1
+ "use strict";var P=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var X=Object.getOwnPropertyNames;var q=Object.prototype.hasOwnProperty;var B=(e,t)=>{for(var n in t)P(e,n,{get:t[n],enumerable:!0})},Q=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of X(t))!q.call(e,r)&&r!==n&&P(e,r,{get:()=>t[r],enumerable:!(s=J(t,r))||s.enumerable});return e};var Z=e=>Q(P({},"__esModule",{value:!0}),e);var Le={};B(Le,{create:()=>K,default:()=>Oe});module.exports=Z(Le);var ee=class extends Error{code;constructor(e,t){super(t),this.name="PenpalError",this.code=e}},M=ee,te=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof M?e.code:void 0}),re=({name:e,message:t,stack:n,penpalCode:s})=>{let r=s?new M(s,t):new Error(t);return r.name=e,r.stack=n,r},ne=Symbol("Reply"),se=class{value;transferables;#t=ne;constructor(e,t){this.value=e,this.transferables=t?.transferables}},ae=se,v="penpal",N=e=>typeof e=="object"&&e!==null,F=e=>typeof e=="function",oe=e=>N(e)&&e.namespace===v,S=e=>e.type==="SYN",O=e=>e.type==="ACK1",R=e=>e.type==="ACK2",x=e=>e.type==="CALL",U=e=>e.type==="REPLY",ie=e=>e.type==="DESTROY",W=(e,t=[])=>{let n=[];for(let s of Object.keys(e)){let r=e[s];F(r)?n.push([...t,s]):N(r)&&n.push(...W(r,[...t,s]))}return n},de=(e,t)=>{let n=e.reduce((s,r)=>N(s)?s[r]:void 0,t);return F(n)?n:void 0},g=e=>e.join("."),b=(e,t,n)=>({namespace:v,channel:e,type:"REPLY",callId:t,isError:!0,...n instanceof Error?{value:te(n),isSerializedErrorInstance:!0}:{value:n}}),le=(e,t,n,s)=>{let r=!1,o=async i=>{if(r||!x(i))return;s?.(`Received ${g(i.methodPath)}() call`,i);let{methodPath:h,args:l,id:a}=i,d,p;try{let u=de(h,t);if(!u)throw new M("METHOD_NOT_FOUND",`Method \`${g(h)}\` is not found.`);let f=await u(...l);f instanceof ae&&(p=f.transferables,f=await f.value),d={namespace:v,channel:n,type:"REPLY",callId:a,value:f}}catch(u){d=b(n,a,u)}if(!r)try{s?.(`Sending ${g(h)}() reply`,d),e.sendMessage(d,p)}catch(u){throw u.name==="DataCloneError"&&(d=b(n,a,u),s?.(`Sending ${g(h)}() reply`,d),e.sendMessage(d)),u}};return e.addMessageHandler(o),()=>{r=!0,e.removeMessageHandler(o)}},ce=le,$=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,Me=new Set(["apply","call","bind"]),V=(e,t,n=[])=>new Proxy(n.length?()=>{}:Object.create(null),{get(s,r){if(r!=="then")return n.length&&Me.has(r)?Reflect.get(s,r):V(e,t,[...n,r])},apply(s,r,o){return e(n,o)}}),D=e=>new M("CONNECTION_DESTROYED",`Method call ${g(e)}() failed due to destroyed connection`),pe=(e,t,n)=>{let s=!1,r=new Map,o=l=>{if(!U(l))return;let{callId:a,value:d,isError:p,isSerializedErrorInstance:u}=l,f=r.get(a);f&&(r.delete(a),n?.(`Received ${g(f.methodPath)}() call`,l),p?f.reject(u?re(d):d):f.resolve(d))};return e.addMessageHandler(o),{remoteProxy:V((l,a)=>{if(s)throw D(l);let d=$(),p=a[a.length-1],u=p instanceof fe,{timeout:f,transferables:C}=u?p:{},w=u?a.slice(0,-1):a;return new Promise((m,I)=>{let _=f!==void 0?window.setTimeout(()=>{r.delete(d),I(new M("METHOD_CALL_TIMEOUT",`Method call ${g(l)}() timed out after ${f}ms`))},f):void 0;r.set(d,{methodPath:l,resolve:m,reject:I,timeoutId:_});try{let E={namespace:v,channel:t,type:"CALL",id:d,methodPath:l,args:w};n?.(`Sending ${g(l)}() call`,E),e.sendMessage(E,C)}catch(E){I(new M("TRANSMISSION_FAILED",E.message))}})},n),destroy:()=>{s=!0,e.removeMessageHandler(o);for(let{methodPath:l,reject:a,timeoutId:d}of r.values())clearTimeout(d),a(D(l));r.clear()}}},ve=pe,ge=()=>{let e,t;return{promise:new Promise((s,r)=>{e=s,t=r}),resolve:e,reject:t}},ye=ge,T="deprecated-penpal",Ee=e=>N(e)&&"penpal"in e,Ie=e=>e.split("."),k=e=>e.join("."),we=e=>{try{return JSON.stringify(e)}catch{return String(e)}},Y=e=>new M("TRANSMISSION_FAILED",`Unexpected message to translate: ${we(e)}`),me=e=>{if(e.penpal==="syn")return{namespace:v,channel:void 0,type:"SYN",participantId:T};if(e.penpal==="ack")return{namespace:v,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:v,channel:void 0,type:"CALL",id:e.id,methodPath:Ie(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:v,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:v,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw Y(e)},Ae=e=>{if(O(e))return{penpal:"synAck",methodNames:e.methodPaths.map(k)};if(x(e))return{penpal:"call",id:e.id,methodName:k(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 Y(e)},Se=({messenger:e,methods:t,timeout:n,channel:s,log:r})=>{let o=$(),i,h=[],l=!1,a=W(t),{promise:d,resolve:p,reject:u}=ye(),f=n!==void 0?setTimeout(()=>{u(new M("CONNECTION_TIMEOUT",`Connection timed out after ${n}ms`))},n):void 0,C=()=>{for(let c of h)c()},w=()=>{if(l)return;h.push(ce(e,t,s,r));let{remoteProxy:c,destroy:y}=ve(e,s,r);h.push(y),clearTimeout(f),l=!0,p({remoteProxy:c,destroy:C})},m=()=>{let c={namespace:v,type:"SYN",channel:s,participantId:o};r?.("Sending handshake SYN",c);try{e.sendMessage(c)}catch(y){u(new M("TRANSMISSION_FAILED",y.message))}},I=c=>{if(r?.("Received handshake SYN",c),c.participantId===i&&i!==T||(i=c.participantId,m(),!(o>i||i===T)))return;let A={namespace:v,channel:s,type:"ACK1",methodPaths:a};r?.("Sending handshake ACK1",A);try{e.sendMessage(A)}catch(G){u(new M("TRANSMISSION_FAILED",G.message));return}},_=c=>{r?.("Received handshake ACK1",c);let y={namespace:v,channel:s,type:"ACK2"};r?.("Sending handshake ACK2",y);try{e.sendMessage(y)}catch(A){u(new M("TRANSMISSION_FAILED",A.message));return}w()},E=c=>{r?.("Received handshake ACK2",c),w()},L=c=>{S(c)&&I(c),O(c)&&_(c),R(c)&&E(c)};return e.addMessageHandler(L),h.push(()=>e.removeMessageHandler(L)),m(),d},Ne=Se,Ce=e=>{let t=!1,n;return(...s)=>(t||(t=!0,n=e(...s)),n)},_e=Ce,H=new WeakSet,Pe=({messenger:e,methods:t={},timeout:n,channel:s,log:r})=>{if(!e)throw new M("INVALID_ARGUMENT","messenger must be defined");if(H.has(e))throw new M("INVALID_ARGUMENT","A messenger can only be used for a single connection");H.add(e);let o=[e.destroy],i=_e(a=>{if(a){let d={namespace:v,channel:s,type:"DESTROY"};try{e.sendMessage(d)}catch{}}for(let d of o)d();r?.("Connection destroyed")}),h=a=>oe(a)&&a.channel===s;return{promise:(async()=>{try{e.initialize({log:r,validateReceivedMessage:h}),e.addMessageHandler(p=>{ie(p)&&i(!1)});let{remoteProxy:a,destroy:d}=await Ne({messenger:e,methods:t,timeout:n,channel:s,log:r});return o.push(d),a}catch(a){throw i(!0),a}})(),destroy:()=>{i(!0)}}},j=Pe,Re=class{#t;#s;#r;#i;#a;#n=new Set;#e;#o=!1;constructor({remoteWindow:e,allowedOrigins:t}){if(!e)throw new M("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.#i=t,window.addEventListener("message",this.#h)};sendMessage=(e,t)=>{if(S(e)){let n=this.#d(e);this.#t.postMessage(e,{targetOrigin:n,transfer:t});return}if(O(e)||this.#o){let n=this.#o?Ae(e):e,s=this.#d(e);this.#t.postMessage(n,{targetOrigin:s,transfer:t});return}if(R(e)){let{port1:n,port2:s}=new MessageChannel;this.#e=n,n.addEventListener("message",this.#l),n.start();let r=[s,...t||[]],o=this.#d(e);this.#t.postMessage(e,{targetOrigin:o,transfer:r});return}if(this.#e){this.#e.postMessage(e,{transfer:t});return}throw new M("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.#c(),this.#n.clear()};#u=e=>this.#s.some(t=>t instanceof RegExp?t.test(e):t===e||t==="*");#d=e=>{if(S(e))return"*";if(!this.#a)throw new M("TRANSMISSION_FAILED","Cannot send message because the remote origin is not established");return this.#a==="null"&&this.#s.includes("*")?"*":this.#a};#c=()=>{this.#e?.removeEventListener("message",this.#l),this.#e?.close(),this.#e=void 0};#h=({source:e,origin:t,ports:n,data:s})=>{if(e===this.#t){if(Ee(s)){this.#r?.("Please upgrade the child window to the latest version of Penpal."),this.#o=!0;try{s=me(s)}catch(r){this.#r?.(`Failed to translate deprecated message: ${r.message}`);return}}if(this.#i?.(s)){if(!this.#u(t)){this.#r?.(`Received a message from origin \`${t}\` which did not match allowed origins \`[${this.#s.join(", ")}]\``);return}if(S(s)&&(this.#c(),this.#a=t),R(s)&&!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.#l),this.#e.start()}for(let r of this.#n)r(s)}}};#l=({data:e})=>{if(this.#i?.(e))for(let t of this.#n)t(e)}},z=Re;var Te=()=>{let e=new Map,t=(r,o,i)=>{let h=i?(a=>{o(a),n(r,h)}):o,l=e.get(r);return l?l.add(h):e.set(r,new Set([h])),()=>n(r,h)},n=(r,o)=>{if(!o){e.delete(r);return}let i=e.get(r);i&&i.delete(o)};return{onMessage:t,offMessage:n,emitMessage:(r,o)=>{let i=e.get(r);if(i)return i.forEach(h=>h(o)),!0}}},K=(e,t=["__AllowedOrigins__"])=>{if(!e.contentWindow)throw new Error("iframe contentWindow is null");let{onMessage:n,offMessage:s,emitMessage:r}=Te(),o=j({messenger:new z({remoteWindow:e.contentWindow,allowedOrigins:t}),channel:"iframe-bridge-channel",methods:{onMessage(l,a){return r(l,a)}}}),i=!1;return o.promise.then(()=>{i=!0}),{api:new Proxy({},{get(l,a){return async(...d)=>await o.promise.then(p=>p[a](...d))}}),onMessage:n,offMessage:s,isInit:()=>i,onInit(l){if(i){l();return}o.promise.then(()=>{l()})},destroy:o.destroy}},Oe={create:K};0&&(module.exports={create});
@@ -0,0 +1 @@
1
+ var K=class extends Error{code;constructor(e,r){super(r),this.name="PenpalError",this.code=e}},M=K,G=e=>({name:e.name,message:e.message,stack:e.stack,penpalCode:e instanceof M?e.code:void 0}),J=({name:e,message:r,stack:n,penpalCode:s})=>{let t=s?new M(s,r):new Error(r);return t.name=e,t.stack=n,t},X=Symbol("Reply"),q=class{value;transferables;#t=X;constructor(e,r){this.value=e,this.transferables=r?.transferables}},B=q,v="penpal",N=e=>typeof e=="object"&&e!==null,H=e=>typeof e=="function",Q=e=>N(e)&&e.namespace===v,S=e=>e.type==="SYN",T=e=>e.type==="ACK1",P=e=>e.type==="ACK2",F=e=>e.type==="CALL",x=e=>e.type==="REPLY",Z=e=>e.type==="DESTROY",U=(e,r=[])=>{let n=[];for(let s of Object.keys(e)){let t=e[s];H(t)?n.push([...r,s]):N(t)&&n.push(...U(t,[...r,s]))}return n},ee=(e,r)=>{let n=e.reduce((s,t)=>N(s)?s[t]:void 0,r);return H(n)?n:void 0},g=e=>e.join("."),L=(e,r,n)=>({namespace:v,channel:e,type:"REPLY",callId:r,isError:!0,...n instanceof Error?{value:G(n),isSerializedErrorInstance:!0}:{value:n}}),te=(e,r,n,s)=>{let t=!1,o=async i=>{if(t||!F(i))return;s?.(`Received ${g(i.methodPath)}() call`,i);let{methodPath:h,args:l,id:a}=i,d,p;try{let u=ee(h,r);if(!u)throw new M("METHOD_NOT_FOUND",`Method \`${g(h)}\` is not found.`);let f=await u(...l);f instanceof B&&(p=f.transferables,f=await f.value),d={namespace:v,channel:n,type:"REPLY",callId:a,value:f}}catch(u){d=L(n,a,u)}if(!t)try{s?.(`Sending ${g(h)}() reply`,d),e.sendMessage(d,p)}catch(u){throw u.name==="DataCloneError"&&(d=L(n,a,u),s?.(`Sending ${g(h)}() reply`,d),e.sendMessage(d)),u}};return e.addMessageHandler(o),()=>{t=!0,e.removeMessageHandler(o)}},re=te,W=crypto.randomUUID?.bind(crypto)??(()=>new Array(4).fill(0).map(()=>Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(16)).join("-")),ne=Symbol("CallOptions"),se=class{transferables;timeout;#t=ne;constructor(e){this.transferables=e?.transferables,this.timeout=e?.timeout}},ae=se,oe=new Set(["apply","call","bind"]),$=(e,r,n=[])=>new Proxy(n.length?()=>{}:Object.create(null),{get(s,t){if(t!=="then")return n.length&&oe.has(t)?Reflect.get(s,t):$(e,r,[...n,t])},apply(s,t,o){return e(n,o)}}),b=e=>new M("CONNECTION_DESTROYED",`Method call ${g(e)}() failed due to destroyed connection`),ie=(e,r,n)=>{let s=!1,t=new Map,o=l=>{if(!x(l))return;let{callId:a,value:d,isError:p,isSerializedErrorInstance:u}=l,f=t.get(a);f&&(t.delete(a),n?.(`Received ${g(f.methodPath)}() call`,l),p?f.reject(u?J(d):d):f.resolve(d))};return e.addMessageHandler(o),{remoteProxy:$((l,a)=>{if(s)throw b(l);let d=W(),p=a[a.length-1],u=p instanceof ae,{timeout:f,transferables:C}=u?p:{},w=u?a.slice(0,-1):a;return new Promise((m,I)=>{let _=f!==void 0?window.setTimeout(()=>{t.delete(d),I(new M("METHOD_CALL_TIMEOUT",`Method call ${g(l)}() timed out after ${f}ms`))},f):void 0;t.set(d,{methodPath:l,resolve:m,reject:I,timeoutId:_});try{let E={namespace:v,channel:r,type:"CALL",id:d,methodPath:l,args:w};n?.(`Sending ${g(l)}() call`,E),e.sendMessage(E,C)}catch(E){I(new M("TRANSMISSION_FAILED",E.message))}})},n),destroy:()=>{s=!0,e.removeMessageHandler(o);for(let{methodPath:l,reject:a,timeoutId:d}of t.values())clearTimeout(d),a(b(l));t.clear()}}},de=ie,le=()=>{let e,r;return{promise:new Promise((s,t)=>{e=s,r=t}),resolve:e,reject:r}},ce=le,R="deprecated-penpal",he=e=>N(e)&&"penpal"in e,ue=e=>e.split("."),D=e=>e.join("."),fe=e=>{try{return JSON.stringify(e)}catch{return String(e)}},V=e=>new M("TRANSMISSION_FAILED",`Unexpected message to translate: ${fe(e)}`),Me=e=>{if(e.penpal==="syn")return{namespace:v,channel:void 0,type:"SYN",participantId:R};if(e.penpal==="ack")return{namespace:v,channel:void 0,type:"ACK2"};if(e.penpal==="call")return{namespace:v,channel:void 0,type:"CALL",id:e.id,methodPath:ue(e.methodName),args:e.args};if(e.penpal==="reply")return e.resolution==="fulfilled"?{namespace:v,channel:void 0,type:"REPLY",callId:e.id,value:e.returnValue}:{namespace:v,channel:void 0,type:"REPLY",callId:e.id,isError:!0,...e.returnValueIsError?{value:e.returnValue,isSerializedErrorInstance:!0}:{value:e.returnValue}};throw V(e)},pe=e=>{if(T(e))return{penpal:"synAck",methodNames:e.methodPaths.map(D)};if(F(e))return{penpal:"call",id:e.id,methodName:D(e.methodPath),args:e.args};if(x(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 V(e)},ve=({messenger:e,methods:r,timeout:n,channel:s,log:t})=>{let o=W(),i,h=[],l=!1,a=U(r),{promise:d,resolve:p,reject:u}=ce(),f=n!==void 0?setTimeout(()=>{u(new M("CONNECTION_TIMEOUT",`Connection timed out after ${n}ms`))},n):void 0,C=()=>{for(let c of h)c()},w=()=>{if(l)return;h.push(re(e,r,s,t));let{remoteProxy:c,destroy:y}=de(e,s,t);h.push(y),clearTimeout(f),l=!0,p({remoteProxy:c,destroy:C})},m=()=>{let c={namespace:v,type:"SYN",channel:s,participantId:o};t?.("Sending handshake SYN",c);try{e.sendMessage(c)}catch(y){u(new M("TRANSMISSION_FAILED",y.message))}},I=c=>{if(t?.("Received handshake SYN",c),c.participantId===i&&i!==R||(i=c.participantId,m(),!(o>i||i===R)))return;let A={namespace:v,channel:s,type:"ACK1",methodPaths:a};t?.("Sending handshake ACK1",A);try{e.sendMessage(A)}catch(z){u(new M("TRANSMISSION_FAILED",z.message));return}},_=c=>{t?.("Received handshake ACK1",c);let y={namespace:v,channel:s,type:"ACK2"};t?.("Sending handshake ACK2",y);try{e.sendMessage(y)}catch(A){u(new M("TRANSMISSION_FAILED",A.message));return}w()},E=c=>{t?.("Received handshake ACK2",c),w()},O=c=>{S(c)&&I(c),T(c)&&_(c),P(c)&&E(c)};return e.addMessageHandler(O),h.push(()=>e.removeMessageHandler(O)),m(),d},ge=ve,ye=e=>{let r=!1,n;return(...s)=>(r||(r=!0,n=e(...s)),n)},Ee=ye,k=new WeakSet,Ie=({messenger:e,methods:r={},timeout:n,channel:s,log:t})=>{if(!e)throw new M("INVALID_ARGUMENT","messenger must be defined");if(k.has(e))throw new M("INVALID_ARGUMENT","A messenger can only be used for a single connection");k.add(e);let o=[e.destroy],i=Ee(a=>{if(a){let d={namespace:v,channel:s,type:"DESTROY"};try{e.sendMessage(d)}catch{}}for(let d of o)d();t?.("Connection destroyed")}),h=a=>Q(a)&&a.channel===s;return{promise:(async()=>{try{e.initialize({log:t,validateReceivedMessage:h}),e.addMessageHandler(p=>{Z(p)&&i(!1)});let{remoteProxy:a,destroy:d}=await ge({messenger:e,methods:r,timeout:n,channel:s,log:t});return o.push(d),a}catch(a){throw i(!0),a}})(),destroy:()=>{i(!0)}}},Y=Ie,we=class{#t;#s;#r;#i;#a;#n=new Set;#e;#o=!1;constructor({remoteWindow:e,allowedOrigins:r}){if(!e)throw new M("INVALID_ARGUMENT","remoteWindow must be defined");this.#t=e,this.#s=r?.length?r:[window.origin]}initialize=({log:e,validateReceivedMessage:r})=>{this.#r=e,this.#i=r,window.addEventListener("message",this.#h)};sendMessage=(e,r)=>{if(S(e)){let n=this.#d(e);this.#t.postMessage(e,{targetOrigin:n,transfer:r});return}if(T(e)||this.#o){let n=this.#o?pe(e):e,s=this.#d(e);this.#t.postMessage(n,{targetOrigin:s,transfer:r});return}if(P(e)){let{port1:n,port2:s}=new MessageChannel;this.#e=n,n.addEventListener("message",this.#l),n.start();let t=[s,...r||[]],o=this.#d(e);this.#t.postMessage(e,{targetOrigin:o,transfer:t});return}if(this.#e){this.#e.postMessage(e,{transfer:r});return}throw new M("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.#c(),this.#n.clear()};#u=e=>this.#s.some(r=>r instanceof RegExp?r.test(e):r===e||r==="*");#d=e=>{if(S(e))return"*";if(!this.#a)throw new M("TRANSMISSION_FAILED","Cannot send message because the remote origin is not established");return this.#a==="null"&&this.#s.includes("*")?"*":this.#a};#c=()=>{this.#e?.removeEventListener("message",this.#l),this.#e?.close(),this.#e=void 0};#h=({source:e,origin:r,ports:n,data:s})=>{if(e===this.#t){if(he(s)){this.#r?.("Please upgrade the child window to the latest version of Penpal."),this.#o=!0;try{s=Me(s)}catch(t){this.#r?.(`Failed to translate deprecated message: ${t.message}`);return}}if(this.#i?.(s)){if(!this.#u(r)){this.#r?.(`Received a message from origin \`${r}\` which did not match allowed origins \`[${this.#s.join(", ")}]\``);return}if(S(s)&&(this.#c(),this.#a=r),P(s)&&!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.#l),this.#e.start()}for(let t of this.#n)t(s)}}};#l=({data:e})=>{if(this.#i?.(e))for(let r of this.#n)r(e)}},j=we;var me=()=>{let e=new Map,r=(t,o,i)=>{let h=i?(a=>{o(a),n(t,h)}):o,l=e.get(t);return l?l.add(h):e.set(t,new Set([h])),()=>n(t,h)},n=(t,o)=>{if(!o){e.delete(t);return}let i=e.get(t);i&&i.delete(o)};return{onMessage:r,offMessage:n,emitMessage:(t,o)=>{let i=e.get(t);if(i)return i.forEach(h=>h(o)),!0}}},Ae=(e,r=["__AllowedOrigins__"])=>{if(!e.contentWindow)throw new Error("iframe contentWindow is null");let{onMessage:n,offMessage:s,emitMessage:t}=me(),o=Y({messenger:new j({remoteWindow:e.contentWindow,allowedOrigins:r}),channel:"iframe-bridge-channel",methods:{onMessage(l,a){return t(l,a)}}}),i=!1;return o.promise.then(()=>{i=!0}),{api:new Proxy({},{get(l,a){return async(...d)=>await o.promise.then(p=>p[a](...d))}}),onMessage:n,offMessage:s,isInit:()=>i,onInit(l){if(i){l();return}o.promise.then(()=>{l()})},destroy:o.destroy}},Te={create:Ae};export{Ae as create,Te as default};
package/dist/index.d.mts CHANGED
@@ -1,8 +1,17 @@
1
- /** 定义一个 bridge,暴露方法给 iframe 父/子窗口调用 */
2
- declare const defineBridge: <TEmit extends Record<string, object | string | number | boolean | null | undefined>>(name: string, methods: Record<string, (...args: any[]) => any>) => {
1
+ type BridgeEventArgs<T> = [T] extends [void] ? [data?: T] : [data: T];
2
+ type BridgeMethods = Record<string, (...args: any[]) => any>;
3
+ /** 在父窗口定义 bridge,暴露方法给 iframe 调用 */
4
+ declare const defineBridge: <TEmit extends object = Record<string, unknown>>(name: string, methods: BridgeMethods) => {
3
5
  create(iframe: HTMLIFrameElement, allowedOrigins?: string[]): Promise<{
4
- emit<T extends keyof TEmit>(type: T, data: TEmit[T]): void;
6
+ emit<T extends keyof TEmit>(type: T, ...args: BridgeEventArgs<TEmit[T]>): void;
7
+ }>;
8
+ };
9
+ /** 在 iframe 中定义 bridge,暴露方法给父窗口调用 */
10
+ declare const defineIframeBridge: <TEmit extends object = Record<string, unknown>>(name: string, methods: BridgeMethods) => {
11
+ connect(allowedOrigins?: string[]): Promise<{
12
+ emit<T extends keyof TEmit>(type: T, ...args: BridgeEventArgs<TEmit[T]>): void;
13
+ destroy: () => void;
5
14
  }>;
6
15
  };
7
16
 
8
- export { defineBridge };
17
+ export { defineBridge, defineIframeBridge };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,17 @@
1
- /** 定义一个 bridge,暴露方法给 iframe 父/子窗口调用 */
2
- declare const defineBridge: <TEmit extends Record<string, object | string | number | boolean | null | undefined>>(name: string, methods: Record<string, (...args: any[]) => any>) => {
1
+ type BridgeEventArgs<T> = [T] extends [void] ? [data?: T] : [data: T];
2
+ type BridgeMethods = Record<string, (...args: any[]) => any>;
3
+ /** 在父窗口定义 bridge,暴露方法给 iframe 调用 */
4
+ declare const defineBridge: <TEmit extends object = Record<string, unknown>>(name: string, methods: BridgeMethods) => {
3
5
  create(iframe: HTMLIFrameElement, allowedOrigins?: string[]): Promise<{
4
- emit<T extends keyof TEmit>(type: T, data: TEmit[T]): void;
6
+ emit<T extends keyof TEmit>(type: T, ...args: BridgeEventArgs<TEmit[T]>): void;
7
+ }>;
8
+ };
9
+ /** 在 iframe 中定义 bridge,暴露方法给父窗口调用 */
10
+ declare const defineIframeBridge: <TEmit extends object = Record<string, unknown>>(name: string, methods: BridgeMethods) => {
11
+ connect(allowedOrigins?: string[]): Promise<{
12
+ emit<T extends keyof TEmit>(type: T, ...args: BridgeEventArgs<TEmit[T]>): void;
13
+ destroy: () => void;
5
14
  }>;
6
15
  };
7
16
 
8
- export { defineBridge };
17
+ export { defineBridge, defineIframeBridge };
package/dist/index.js CHANGED
@@ -20,7 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- defineBridge: () => defineBridge
23
+ defineBridge: () => defineBridge,
24
+ defineIframeBridge: () => defineIframeBridge
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
26
27
  var import_penpal = require("penpal");
@@ -40,14 +41,38 @@ var defineBridge = (name, methods) => {
40
41
  });
41
42
  const remote = await conn.promise;
42
43
  return {
43
- emit(type, data) {
44
+ emit(type, ...args) {
45
+ const [data] = args;
44
46
  remote.onMessage(type, data);
45
47
  }
46
48
  };
47
49
  }
48
50
  };
49
51
  };
52
+ var defineIframeBridge = (name, methods) => {
53
+ return {
54
+ async connect(allowedOrigins = ["*"]) {
55
+ const conn = (0, import_penpal.connect)({
56
+ messenger: new import_penpal.WindowMessenger({
57
+ remoteWindow: window.parent,
58
+ allowedOrigins
59
+ }),
60
+ channel: "iframe-bridge-channel",
61
+ methods
62
+ });
63
+ const remote = await conn.promise;
64
+ return {
65
+ emit(type, ...args) {
66
+ const [data] = args;
67
+ remote.onMessage(type, data);
68
+ },
69
+ destroy: conn.destroy
70
+ };
71
+ }
72
+ };
73
+ };
50
74
  // Annotate the CommonJS export names for ESM import in node:
51
75
  0 && (module.exports = {
52
- defineBridge
76
+ defineBridge,
77
+ defineIframeBridge
53
78
  });
package/dist/index.mjs CHANGED
@@ -16,13 +16,37 @@ var defineBridge = (name, methods) => {
16
16
  });
17
17
  const remote = await conn.promise;
18
18
  return {
19
- emit(type, data) {
19
+ emit(type, ...args) {
20
+ const [data] = args;
20
21
  remote.onMessage(type, data);
21
22
  }
22
23
  };
23
24
  }
24
25
  };
25
26
  };
27
+ var defineIframeBridge = (name, methods) => {
28
+ return {
29
+ async connect(allowedOrigins = ["*"]) {
30
+ const conn = connect({
31
+ messenger: new WindowMessenger({
32
+ remoteWindow: window.parent,
33
+ allowedOrigins
34
+ }),
35
+ channel: "iframe-bridge-channel",
36
+ methods
37
+ });
38
+ const remote = await conn.promise;
39
+ return {
40
+ emit(type, ...args) {
41
+ const [data] = args;
42
+ remote.onMessage(type, data);
43
+ },
44
+ destroy: conn.destroy
45
+ };
46
+ }
47
+ };
48
+ };
26
49
  export {
27
- defineBridge
50
+ defineBridge,
51
+ defineIframeBridge
28
52
  };
package/dist/mini/core.js CHANGED
@@ -1 +1 @@
1
- "use strict";var a=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var m=(n,e)=>{for(var t in e)a(n,t,{get:e[t],enumerable:!0})},h=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of u(e))!w.call(n,s)&&s!==t&&a(n,s,{get:()=>e[s],enumerable:!(o=l(e,s))||o.enumerable});return n};var p=n=>h(a({},"__esModule",{value:!0}),n);var I={};m(I,{default:()=>x,isInit:()=>_,offMessage:()=>c,onInit:()=>F,onMessage:()=>M});module.exports=p(I);var i=require("penpal"),r=new Map,g=(0,i.connect)({messenger:new i.WindowMessenger({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(n,e){let t=r.get(n);if(t)return t.forEach(o=>o(e)),!0}}}),x=new Proxy({},{get(n,e){return async t=>await g.promise.then(o=>o[e](t))}}),M=(n,e,t)=>{let o=t?(d=>{e(d),c(n,e)}):e,s=r.get(n);return s?s.add(o):r.set(n,new Set([o])),()=>c(n,o)},c=(n,e)=>{if(!e){r.delete(n);return}let t=r.get(n);t&&t.delete(e)},f=!1;g.promise.then(()=>{f=!0});var _=()=>f,F=n=>{if(f){n();return}g.promise.then(()=>{n()})};0&&(module.exports={isInit,offMessage,onInit,onMessage});
1
+ "use strict";var a=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var w=Object.prototype.hasOwnProperty;var m=(n,e)=>{for(var t in e)a(n,t,{get:e[t],enumerable:!0})},h=(n,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of u(e))!w.call(n,s)&&s!==t&&a(n,s,{get:()=>e[s],enumerable:!(o=l(e,s))||o.enumerable});return n};var p=n=>h(a({},"__esModule",{value:!0}),n);var I={};m(I,{default:()=>x,isInit:()=>_,offMessage:()=>c,onInit:()=>F,onMessage:()=>M});module.exports=p(I);var i=require("penpal"),r=new Map,g=(0,i.connect)({messenger:new i.WindowMessenger({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(n,e){let t=r.get(n);if(t)return t.forEach(o=>o(e)),!0}}}),x=new Proxy({},{get(n,e){return async(...t)=>await g.promise.then(o=>o[e](...t))}}),M=(n,e,t)=>{let o=t?(d=>{e(d),c(n,o)}):e,s=r.get(n);return s?s.add(o):r.set(n,new Set([o])),()=>c(n,o)},c=(n,e)=>{if(!e){r.delete(n);return}let t=r.get(n);t&&t.delete(e)},f=!1;g.promise.then(()=>{f=!0});var _=()=>f,F=n=>{if(f){n();return}g.promise.then(()=>{n()})};0&&(module.exports={isInit,offMessage,onInit,onMessage});
@@ -1 +1 @@
1
- import{WindowMessenger as f,connect as d}from"penpal";var s=new Map,r=d({messenger:new f({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(n,e){let t=s.get(n);if(t)return t.forEach(o=>o(e)),!0}}}),u=new Proxy({},{get(n,e){return async t=>await r.promise.then(o=>o[e](t))}}),w=(n,e,t)=>{let o=t?(g=>{e(g),c(n,e)}):e,a=s.get(n);return a?a.add(o):s.set(n,new Set([o])),()=>c(n,o)},c=(n,e)=>{if(!e){s.delete(n);return}let t=s.get(n);t&&t.delete(e)},i=!1;r.promise.then(()=>{i=!0});var m=()=>i,h=n=>{if(i){n();return}r.promise.then(()=>{n()})};export{u as default,m as isInit,c as offMessage,h as onInit,w as onMessage};
1
+ import{WindowMessenger as f,connect as d}from"penpal";var s=new Map,r=d({messenger:new f({remoteWindow:window.parent,allowedOrigins:["__AllowedOrigins__"]}),channel:"iframe-bridge-channel",methods:{onMessage(n,e){let t=s.get(n);if(t)return t.forEach(o=>o(e)),!0}}}),u=new Proxy({},{get(n,e){return async(...t)=>await r.promise.then(o=>o[e](...t))}}),w=(n,e,t)=>{let o=t?(g=>{e(g),c(n,o)}):e,a=s.get(n);return a?a.add(o):s.set(n,new Set([o])),()=>c(n,o)},c=(n,e)=>{if(!e){s.delete(n);return}let t=s.get(n);t&&t.delete(e)},i=!1;r.promise.then(()=>{i=!0});var m=()=>i,h=n=>{if(i){n();return}r.promise.then(()=>{n()})};export{u as default,m as isInit,c as offMessage,h as onInit,w as onMessage};
@@ -0,0 +1 @@
1
+ "use strict";var u=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var p=(n,t)=>{for(var r in t)u(n,r,{get:t[r],enumerable:!0})},y=(n,t,r,c)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of M(t))!h.call(n,e)&&e!==r&&u(n,e,{get:()=>t[e],enumerable:!(c=w(t,e))||c.enumerable});return n};var F=n=>y(u({},"__esModule",{value:!0}),n);var x={};p(x,{create:()=>d,default:()=>_});module.exports=F(x);var f=require("penpal"),W=()=>{let n=new Map,t=(e,s,o)=>{let a=o?(g=>{s(g),r(e,a)}):s,i=n.get(e);return i?i.add(a):n.set(e,new Set([a])),()=>r(e,a)},r=(e,s)=>{if(!s){n.delete(e);return}let o=n.get(e);o&&o.delete(s)};return{onMessage:t,offMessage:r,emitMessage:(e,s)=>{let o=n.get(e);if(o)return o.forEach(a=>a(s)),!0}}},d=(n,t=["__AllowedOrigins__"])=>{if(!n.contentWindow)throw new Error("iframe contentWindow is null");let{onMessage:r,offMessage:c,emitMessage:e}=W(),s=(0,f.connect)({messenger:new f.WindowMessenger({remoteWindow:n.contentWindow,allowedOrigins:t}),channel:"iframe-bridge-channel",methods:{onMessage(i,g){return e(i,g)}}}),o=!1;return s.promise.then(()=>{o=!0}),{api:new Proxy({},{get(i,g){return async(...m)=>await s.promise.then(l=>l[g](...m))}}),onMessage:r,offMessage:c,isInit:()=>o,onInit(i){if(o){i();return}s.promise.then(()=>{i()})},destroy:s.destroy}},_={create:d};0&&(module.exports={create});
@@ -0,0 +1 @@
1
+ import{WindowMessenger as d,connect as m}from"penpal";var l=()=>{let s=new Map,c=(n,e,t)=>{let r=t?(a=>{e(a),i(n,r)}):e,o=s.get(n);return o?o.add(r):s.set(n,new Set([r])),()=>i(n,r)},i=(n,e)=>{if(!e){s.delete(n);return}let t=s.get(n);t&&t.delete(e)};return{onMessage:c,offMessage:i,emitMessage:(n,e)=>{let t=s.get(n);if(t)return t.forEach(r=>r(e)),!0}}},w=(s,c=["__AllowedOrigins__"])=>{if(!s.contentWindow)throw new Error("iframe contentWindow is null");let{onMessage:i,offMessage:g,emitMessage:n}=l(),e=m({messenger:new d({remoteWindow:s.contentWindow,allowedOrigins:c}),channel:"iframe-bridge-channel",methods:{onMessage(o,a){return n(o,a)}}}),t=!1;return e.promise.then(()=>{t=!0}),{api:new Proxy({},{get(o,a){return async(...f)=>await e.promise.then(u=>u[a](...f))}}),onMessage:i,offMessage:g,isInit:()=>t,onInit(o){if(t){o();return}e.promise.then(()=>{o()})},destroy:e.destroy}},h={create:w};export{w as create,h as default};
package/dist/vite.js CHANGED
@@ -40,7 +40,7 @@ var fs = __toESM(require("fs"));
40
40
  // package.json
41
41
  var package_default = {
42
42
  name: "iframe-bridge-kit",
43
- version: "1.0.0",
43
+ version: "1.1.0",
44
44
  description: "A type-safe communication bridge for iframes. Define strongly typed RPC APIs for cross-window messaging with ease.",
45
45
  main: "dist/index.js",
46
46
  module: "dist/index.mjs",
@@ -248,7 +248,7 @@ function parseBridgeFromCode(code, filePath) {
248
248
  collectTypeImports(stmt);
249
249
  }
250
250
  }
251
- const defineBridgeNames = /* @__PURE__ */ new Set();
251
+ const bridgeFactories = /* @__PURE__ */ new Map();
252
252
  for (const stmt of sourceFile.statements) {
253
253
  if (ts.isImportDeclaration(stmt) && ts.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text === packageName) {
254
254
  const namedBindings = stmt.importClause?.namedBindings;
@@ -256,17 +256,21 @@ function parseBridgeFromCode(code, filePath) {
256
256
  for (const element of namedBindings.elements) {
257
257
  const originalName = element.propertyName?.text ?? element.name.text;
258
258
  if (originalName === "defineBridge") {
259
- defineBridgeNames.add(element.name.text);
259
+ bridgeFactories.set(element.name.text, "child");
260
+ }
261
+ if (originalName === "defineIframeBridge") {
262
+ bridgeFactories.set(element.name.text, "parent");
260
263
  }
261
264
  }
262
265
  }
263
266
  }
264
267
  }
265
- if (defineBridgeNames.size === 0) {
268
+ if (bridgeFactories.size === 0) {
266
269
  return { results, cleanup };
267
270
  }
268
271
  const visit = (node) => {
269
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && defineBridgeNames.has(node.expression.text)) {
272
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && bridgeFactories.has(node.expression.text)) {
273
+ const target = bridgeFactories.get(node.expression.text);
270
274
  const [nameArg, methodsArg] = node.arguments;
271
275
  if (!nameArg || !ts.isStringLiteral(nameArg)) {
272
276
  return;
@@ -363,8 +367,12 @@ function parseBridgeFromCode(code, filePath) {
363
367
  }
364
368
  }
365
369
  const emitMap = [];
370
+ let emitTypeName;
366
371
  if (node.typeArguments && node.typeArguments.length > 0) {
367
372
  const emitTypeNode = node.typeArguments[0];
373
+ if (ts.isTypeReferenceNode(emitTypeNode) && ts.isIdentifier(emitTypeNode.typeName)) {
374
+ emitTypeName = emitTypeNode.typeName.text;
375
+ }
368
376
  const emitType = checker.getTypeFromTypeNode(emitTypeNode);
369
377
  emitType.getProperties().forEach((prop) => {
370
378
  const name = prop.getName();
@@ -378,11 +386,13 @@ function parseBridgeFromCode(code, filePath) {
378
386
  mergeImports(bridgeImports, typeImports);
379
387
  results.push({
380
388
  name: bridgeName,
389
+ target,
381
390
  methods,
382
391
  sourceFile: filePath,
383
392
  typeDeclarations,
384
393
  imports: bridgeImports,
385
- emitMap
394
+ emitMap,
395
+ emitTypeName
386
396
  });
387
397
  }
388
398
  ts.forEachChild(node, visit);
@@ -554,6 +564,52 @@ function generateDtsContent(info, outDir, preserveModules = []) {
554
564
  lines.push("");
555
565
  }
556
566
  }
567
+ const localTypeDeclarations = info.typeDeclarations.filter(({ name }) => name !== info.emitTypeName && name !== "EmitMap");
568
+ if (localTypeDeclarations.length > 0) {
569
+ lines.push("// Local type definitions");
570
+ for (const { content } of localTypeDeclarations) {
571
+ lines.push(content);
572
+ lines.push("");
573
+ }
574
+ }
575
+ if (info.target === "parent") {
576
+ if (processedEmitTypes.length > 0) {
577
+ lines.push("export interface EmitMap {");
578
+ processedEmitTypes.forEach((e) => {
579
+ lines.push(` "${e.name}": ${e.type};`);
580
+ });
581
+ lines.push("}");
582
+ lines.push("");
583
+ }
584
+ lines.push("export interface BridgeConnection {");
585
+ lines.push(" api: {");
586
+ lines.push(
587
+ ...processedMethods.map(
588
+ (m) => (m.jsdoc ? ` ${m.jsdoc}
589
+ ` : "") + ` ${m.name}: (${m.params}) => ${m.returnType},`
590
+ )
591
+ );
592
+ lines.push(" };");
593
+ if (processedEmitTypes.length > 0) {
594
+ lines.push(" onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
595
+ lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
596
+ lines.push(" offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
597
+ lines.push(" offMessage(type: string, fn?: Function): void;");
598
+ } else {
599
+ lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
600
+ lines.push(" offMessage(type: string, fn?: Function): void;");
601
+ }
602
+ lines.push(" isInit(): boolean;");
603
+ lines.push(" onInit(cb: Function): void;");
604
+ lines.push(" destroy(): void;");
605
+ lines.push("}");
606
+ lines.push("");
607
+ lines.push("export declare function create(iframe: HTMLIFrameElement, allowedOrigins?: string[]): BridgeConnection;");
608
+ lines.push("declare const bridge: { create: typeof create };");
609
+ lines.push("export default bridge;");
610
+ lines.push("");
611
+ return lines.join("\n");
612
+ }
557
613
  if (processedEmitTypes.length > 0) {
558
614
  lines.push("export interface EmitMap {");
559
615
  processedEmitTypes.forEach((e) => {
@@ -606,7 +662,7 @@ function processFile(filePath, code, options) {
606
662
  const { results: bridges, cleanup } = parseBridgeFromCode(code, filePath);
607
663
  for (const bridge of bridges) {
608
664
  writeDtsFile(bridge, options);
609
- writeBridgeRuntime(bridge.name, options);
665
+ writeBridgeRuntime(bridge, options);
610
666
  }
611
667
  cleanup();
612
668
  return bridges;
@@ -615,7 +671,7 @@ function processFile(filePath, code, options) {
615
671
  return [];
616
672
  }
617
673
  }
618
- function writeBridgeRuntime(bridgeName, options) {
674
+ function writeBridgeRuntime(info, options) {
619
675
  const isFull = options.full !== false;
620
676
  const allowedOrigins = options.allowedOrigins || ["*"];
621
677
  const outDir = options.outDir || "bridges";
@@ -636,14 +692,15 @@ function writeBridgeRuntime(bridgeName, options) {
636
692
  if (!coreDir) {
637
693
  return;
638
694
  }
639
- const absoluteOutDir = path.resolve(process.cwd(), outDir, bridgeName);
695
+ const absoluteOutDir = path.resolve(process.cwd(), outDir, info.name);
640
696
  if (!fs.existsSync(absoluteOutDir)) {
641
697
  fs.mkdirSync(absoluteOutDir, { recursive: true });
642
698
  }
643
699
  const extensions = ["js", "mjs"];
644
700
  const replaceContent = JSON.stringify(allowedOrigins).slice(1, -1);
701
+ const runtimeName = info.target === "parent" ? "parent-core" : "core";
645
702
  for (const ext of extensions) {
646
- const srcFile = path.join(coreDir, `core.${ext}`);
703
+ const srcFile = path.join(coreDir, `${runtimeName}.${ext}`);
647
704
  if (fs.existsSync(srcFile)) {
648
705
  try {
649
706
  let content = fs.readFileSync(srcFile, "utf-8");
package/dist/vite.mjs CHANGED
@@ -6,7 +6,7 @@ import * as fs from "fs";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "iframe-bridge-kit",
9
- version: "1.0.0",
9
+ version: "1.1.0",
10
10
  description: "A type-safe communication bridge for iframes. Define strongly typed RPC APIs for cross-window messaging with ease.",
11
11
  main: "dist/index.js",
12
12
  module: "dist/index.mjs",
@@ -214,7 +214,7 @@ function parseBridgeFromCode(code, filePath) {
214
214
  collectTypeImports(stmt);
215
215
  }
216
216
  }
217
- const defineBridgeNames = /* @__PURE__ */ new Set();
217
+ const bridgeFactories = /* @__PURE__ */ new Map();
218
218
  for (const stmt of sourceFile.statements) {
219
219
  if (ts.isImportDeclaration(stmt) && ts.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text === packageName) {
220
220
  const namedBindings = stmt.importClause?.namedBindings;
@@ -222,17 +222,21 @@ function parseBridgeFromCode(code, filePath) {
222
222
  for (const element of namedBindings.elements) {
223
223
  const originalName = element.propertyName?.text ?? element.name.text;
224
224
  if (originalName === "defineBridge") {
225
- defineBridgeNames.add(element.name.text);
225
+ bridgeFactories.set(element.name.text, "child");
226
+ }
227
+ if (originalName === "defineIframeBridge") {
228
+ bridgeFactories.set(element.name.text, "parent");
226
229
  }
227
230
  }
228
231
  }
229
232
  }
230
233
  }
231
- if (defineBridgeNames.size === 0) {
234
+ if (bridgeFactories.size === 0) {
232
235
  return { results, cleanup };
233
236
  }
234
237
  const visit = (node) => {
235
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && defineBridgeNames.has(node.expression.text)) {
238
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && bridgeFactories.has(node.expression.text)) {
239
+ const target = bridgeFactories.get(node.expression.text);
236
240
  const [nameArg, methodsArg] = node.arguments;
237
241
  if (!nameArg || !ts.isStringLiteral(nameArg)) {
238
242
  return;
@@ -329,8 +333,12 @@ function parseBridgeFromCode(code, filePath) {
329
333
  }
330
334
  }
331
335
  const emitMap = [];
336
+ let emitTypeName;
332
337
  if (node.typeArguments && node.typeArguments.length > 0) {
333
338
  const emitTypeNode = node.typeArguments[0];
339
+ if (ts.isTypeReferenceNode(emitTypeNode) && ts.isIdentifier(emitTypeNode.typeName)) {
340
+ emitTypeName = emitTypeNode.typeName.text;
341
+ }
334
342
  const emitType = checker.getTypeFromTypeNode(emitTypeNode);
335
343
  emitType.getProperties().forEach((prop) => {
336
344
  const name = prop.getName();
@@ -344,11 +352,13 @@ function parseBridgeFromCode(code, filePath) {
344
352
  mergeImports(bridgeImports, typeImports);
345
353
  results.push({
346
354
  name: bridgeName,
355
+ target,
347
356
  methods,
348
357
  sourceFile: filePath,
349
358
  typeDeclarations,
350
359
  imports: bridgeImports,
351
- emitMap
360
+ emitMap,
361
+ emitTypeName
352
362
  });
353
363
  }
354
364
  ts.forEachChild(node, visit);
@@ -520,6 +530,52 @@ function generateDtsContent(info, outDir, preserveModules = []) {
520
530
  lines.push("");
521
531
  }
522
532
  }
533
+ const localTypeDeclarations = info.typeDeclarations.filter(({ name }) => name !== info.emitTypeName && name !== "EmitMap");
534
+ if (localTypeDeclarations.length > 0) {
535
+ lines.push("// Local type definitions");
536
+ for (const { content } of localTypeDeclarations) {
537
+ lines.push(content);
538
+ lines.push("");
539
+ }
540
+ }
541
+ if (info.target === "parent") {
542
+ if (processedEmitTypes.length > 0) {
543
+ lines.push("export interface EmitMap {");
544
+ processedEmitTypes.forEach((e) => {
545
+ lines.push(` "${e.name}": ${e.type};`);
546
+ });
547
+ lines.push("}");
548
+ lines.push("");
549
+ }
550
+ lines.push("export interface BridgeConnection {");
551
+ lines.push(" api: {");
552
+ lines.push(
553
+ ...processedMethods.map(
554
+ (m) => (m.jsdoc ? ` ${m.jsdoc}
555
+ ` : "") + ` ${m.name}: (${m.params}) => ${m.returnType},`
556
+ )
557
+ );
558
+ lines.push(" };");
559
+ if (processedEmitTypes.length > 0) {
560
+ lines.push(" onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
561
+ lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
562
+ lines.push(" offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
563
+ lines.push(" offMessage(type: string, fn?: Function): void;");
564
+ } else {
565
+ lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
566
+ lines.push(" offMessage(type: string, fn?: Function): void;");
567
+ }
568
+ lines.push(" isInit(): boolean;");
569
+ lines.push(" onInit(cb: Function): void;");
570
+ lines.push(" destroy(): void;");
571
+ lines.push("}");
572
+ lines.push("");
573
+ lines.push("export declare function create(iframe: HTMLIFrameElement, allowedOrigins?: string[]): BridgeConnection;");
574
+ lines.push("declare const bridge: { create: typeof create };");
575
+ lines.push("export default bridge;");
576
+ lines.push("");
577
+ return lines.join("\n");
578
+ }
523
579
  if (processedEmitTypes.length > 0) {
524
580
  lines.push("export interface EmitMap {");
525
581
  processedEmitTypes.forEach((e) => {
@@ -572,7 +628,7 @@ function processFile(filePath, code, options) {
572
628
  const { results: bridges, cleanup } = parseBridgeFromCode(code, filePath);
573
629
  for (const bridge of bridges) {
574
630
  writeDtsFile(bridge, options);
575
- writeBridgeRuntime(bridge.name, options);
631
+ writeBridgeRuntime(bridge, options);
576
632
  }
577
633
  cleanup();
578
634
  return bridges;
@@ -581,7 +637,7 @@ function processFile(filePath, code, options) {
581
637
  return [];
582
638
  }
583
639
  }
584
- function writeBridgeRuntime(bridgeName, options) {
640
+ function writeBridgeRuntime(info, options) {
585
641
  const isFull = options.full !== false;
586
642
  const allowedOrigins = options.allowedOrigins || ["*"];
587
643
  const outDir = options.outDir || "bridges";
@@ -602,14 +658,15 @@ function writeBridgeRuntime(bridgeName, options) {
602
658
  if (!coreDir) {
603
659
  return;
604
660
  }
605
- const absoluteOutDir = path.resolve(process.cwd(), outDir, bridgeName);
661
+ const absoluteOutDir = path.resolve(process.cwd(), outDir, info.name);
606
662
  if (!fs.existsSync(absoluteOutDir)) {
607
663
  fs.mkdirSync(absoluteOutDir, { recursive: true });
608
664
  }
609
665
  const extensions = ["js", "mjs"];
610
666
  const replaceContent = JSON.stringify(allowedOrigins).slice(1, -1);
667
+ const runtimeName = info.target === "parent" ? "parent-core" : "core";
611
668
  for (const ext of extensions) {
612
- const srcFile = path.join(coreDir, `core.${ext}`);
669
+ const srcFile = path.join(coreDir, `${runtimeName}.${ext}`);
613
670
  if (fs.existsSync(srcFile)) {
614
671
  try {
615
672
  let content = fs.readFileSync(srcFile, "utf-8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iframe-bridge-kit",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
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",