iframe-bridge-kit 1.0.1 → 1.1.1

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