iframe-bridge-kit 1.1.0 → 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/dist/index.mjs CHANGED
@@ -1,52 +1,167 @@
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, ...args) {
20
- const [data] = args;
21
- remote.onMessage(type, data);
22
- }
23
- };
85
+ return copy2;
86
+ }
87
+ if (!isPlainObject(value)) {
88
+ return value;
24
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();
25
108
  };
26
- };
27
- var defineIframeBridge = (name, methods) => {
28
109
  return {
29
- async connect(allowedOrigins = ["*"]) {
30
- const conn = connect({
31
- messenger: new WindowMessenger({
32
- remoteWindow: window.parent,
33
- allowedOrigins
34
- }),
35
- channel: "iframe-bridge-channel",
36
- methods
37
- });
38
- const remote = await conn.promise;
39
- return {
40
- emit(type, ...args) {
41
- const [data] = args;
42
- remote.onMessage(type, data);
43
- },
44
- destroy: conn.destroy
45
- };
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");
46
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
+ };
47
163
  };
48
164
  };
49
165
  export {
50
- defineBridge,
51
- defineIframeBridge
166
+ defineBridge
52
167
  };
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,o)}):e,s=r.get(n);return s?s.add(o):r.set(n,new Set([o])),()=>c(n,o)},c=(n,e)=>{if(!e){r.delete(n);return}let t=r.get(n);t&&t.delete(e)},f=!1;g.promise.then(()=>{f=!0});var _=()=>f,F=n=>{if(f){n();return}g.promise.then(()=>{n()})};0&&(module.exports={isInit,offMessage,onInit,onMessage});
1
+ "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,o)}):e,a=s.get(n);return a?a.add(o):s.set(n,new Set([o])),()=>c(n,o)},c=(n,e)=>{if(!e){s.delete(n);return}let t=s.get(n);t&&t.delete(e)},i=!1;r.promise.then(()=>{i=!0});var m=()=>i,h=n=>{if(i){n();return}r.promise.then(()=>{n()})};export{u as default,m as isInit,c as offMessage,h as onInit,w as onMessage};
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.1.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);
@@ -248,7 +263,7 @@ function parseBridgeFromCode(code, filePath) {
248
263
  collectTypeImports(stmt);
249
264
  }
250
265
  }
251
- const bridgeFactories = /* @__PURE__ */ new Map();
266
+ const defineBridgeNames = /* @__PURE__ */ new Set();
252
267
  for (const stmt of sourceFile.statements) {
253
268
  if (ts.isImportDeclaration(stmt) && ts.isStringLiteral(stmt.moduleSpecifier) && stmt.moduleSpecifier.text === packageName) {
254
269
  const namedBindings = stmt.importClause?.namedBindings;
@@ -256,21 +271,17 @@ function parseBridgeFromCode(code, filePath) {
256
271
  for (const element of namedBindings.elements) {
257
272
  const originalName = element.propertyName?.text ?? element.name.text;
258
273
  if (originalName === "defineBridge") {
259
- bridgeFactories.set(element.name.text, "child");
260
- }
261
- if (originalName === "defineIframeBridge") {
262
- bridgeFactories.set(element.name.text, "parent");
274
+ defineBridgeNames.add(element.name.text);
263
275
  }
264
276
  }
265
277
  }
266
278
  }
267
279
  }
268
- if (bridgeFactories.size === 0) {
280
+ if (defineBridgeNames.size === 0) {
269
281
  return { results, cleanup };
270
282
  }
271
283
  const visit = (node) => {
272
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && bridgeFactories.has(node.expression.text)) {
273
- const target = bridgeFactories.get(node.expression.text);
284
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && defineBridgeNames.has(node.expression.text)) {
274
285
  const [nameArg, methodsArg] = node.arguments;
275
286
  if (!nameArg || !ts.isStringLiteral(nameArg)) {
276
287
  return;
@@ -367,12 +378,8 @@ function parseBridgeFromCode(code, filePath) {
367
378
  }
368
379
  }
369
380
  const emitMap = [];
370
- let emitTypeName;
371
381
  if (node.typeArguments && node.typeArguments.length > 0) {
372
382
  const emitTypeNode = node.typeArguments[0];
373
- if (ts.isTypeReferenceNode(emitTypeNode) && ts.isIdentifier(emitTypeNode.typeName)) {
374
- emitTypeName = emitTypeNode.typeName.text;
375
- }
376
383
  const emitType = checker.getTypeFromTypeNode(emitTypeNode);
377
384
  emitType.getProperties().forEach((prop) => {
378
385
  const name = prop.getName();
@@ -386,13 +393,11 @@ function parseBridgeFromCode(code, filePath) {
386
393
  mergeImports(bridgeImports, typeImports);
387
394
  results.push({
388
395
  name: bridgeName,
389
- target,
390
396
  methods,
391
397
  sourceFile: filePath,
392
398
  typeDeclarations,
393
399
  imports: bridgeImports,
394
- emitMap,
395
- emitTypeName
400
+ emitMap
396
401
  });
397
402
  }
398
403
  ts.forEachChild(node, visit);
@@ -564,52 +569,6 @@ function generateDtsContent(info, outDir, preserveModules = []) {
564
569
  lines.push("");
565
570
  }
566
571
  }
567
- const localTypeDeclarations = info.typeDeclarations.filter(({ name }) => name !== info.emitTypeName && name !== "EmitMap");
568
- if (localTypeDeclarations.length > 0) {
569
- lines.push("// Local type definitions");
570
- for (const { content } of localTypeDeclarations) {
571
- lines.push(content);
572
- lines.push("");
573
- }
574
- }
575
- if (info.target === "parent") {
576
- if (processedEmitTypes.length > 0) {
577
- lines.push("export interface EmitMap {");
578
- processedEmitTypes.forEach((e) => {
579
- lines.push(` "${e.name}": ${e.type};`);
580
- });
581
- lines.push("}");
582
- lines.push("");
583
- }
584
- lines.push("export interface BridgeConnection {");
585
- lines.push(" api: {");
586
- lines.push(
587
- ...processedMethods.map(
588
- (m) => (m.jsdoc ? ` ${m.jsdoc}
589
- ` : "") + ` ${m.name}: (${m.params}) => ${m.returnType},`
590
- )
591
- );
592
- lines.push(" };");
593
- if (processedEmitTypes.length > 0) {
594
- lines.push(" onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
595
- lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
596
- lines.push(" offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
597
- lines.push(" offMessage(type: string, fn?: Function): void;");
598
- } else {
599
- lines.push(" onMessage(type: string, cb: Function, once?: boolean): () => void;");
600
- lines.push(" offMessage(type: string, fn?: Function): void;");
601
- }
602
- lines.push(" isInit(): boolean;");
603
- lines.push(" onInit(cb: Function): void;");
604
- lines.push(" destroy(): void;");
605
- lines.push("}");
606
- lines.push("");
607
- lines.push("export declare function create(iframe: HTMLIFrameElement, allowedOrigins?: string[]): BridgeConnection;");
608
- lines.push("declare const bridge: { create: typeof create };");
609
- lines.push("export default bridge;");
610
- lines.push("");
611
- return lines.join("\n");
612
- }
613
572
  if (processedEmitTypes.length > 0) {
614
573
  lines.push("export interface EmitMap {");
615
574
  processedEmitTypes.forEach((e) => {
@@ -617,18 +576,10 @@ function generateDtsContent(info, outDir, preserveModules = []) {
617
576
  });
618
577
  lines.push("}");
619
578
  lines.push("");
620
- lines.push("export declare function onMessage<K extends keyof EmitMap>(type: K, cb: (data: EmitMap[K]) => void, once?: boolean): () => void;");
621
- lines.push("export declare function onMessage(type: string, cb: Function, once?: boolean): () => void;");
622
- lines.push("export declare function offMessage<K extends keyof EmitMap>(type: K, fn?: (data: EmitMap[K]) => void): void;");
623
- lines.push("export declare function offMessage(type: string, fn?: Function): void;");
624
- } else {
625
- lines.push("export declare function onMessage(type: string, cb: Function, once?: boolean): () => void;");
626
- lines.push("export declare function offMessage(type: string, fn?: Function): void;");
627
579
  }
628
- lines.push("export declare function isInit(): boolean;");
629
- lines.push("export declare function onInit(cb: Function): void;");
580
+ lines.push("export declare function createBridgeClient(remoteWindow: Window, allowedOrigins?: string[]): BridgeClient;");
630
581
  lines.push("");
631
- lines.push(`export default {} as {`);
582
+ lines.push(`export interface BridgeApi {`);
632
583
  lines.push(
633
584
  ...processedMethods.map(
634
585
  (m) => (m.jsdoc ? ` ${m.jsdoc}
@@ -637,6 +588,24 @@ function generateDtsContent(info, outDir, preserveModules = []) {
637
588
  );
638
589
  lines.push("}");
639
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("");
640
609
  return lines.join("\n");
641
610
  }
642
611
  function writeDtsFile(info, options) {
@@ -662,7 +631,7 @@ function processFile(filePath, code, options) {
662
631
  const { results: bridges, cleanup } = parseBridgeFromCode(code, filePath);
663
632
  for (const bridge of bridges) {
664
633
  writeDtsFile(bridge, options);
665
- writeBridgeRuntime(bridge, options);
634
+ writeBridgeRuntime(bridge.name, options);
666
635
  }
667
636
  cleanup();
668
637
  return bridges;
@@ -671,19 +640,13 @@ function processFile(filePath, code, options) {
671
640
  return [];
672
641
  }
673
642
  }
674
- function writeBridgeRuntime(info, options) {
643
+ function writeBridgeRuntime(bridgeName, options) {
675
644
  const isFull = options.full !== false;
676
645
  const allowedOrigins = options.allowedOrigins || ["*"];
677
646
  const outDir = options.outDir || "bridges";
678
647
  const variant = isFull ? "full" : "mini";
679
- const basePaths = [
680
- // 1. 假设我们在 dist 目录中运行
681
- path.resolve(__dirname, variant),
682
- // 2. 假设我们在 src 目录中运行
683
- path.resolve(__dirname, "../dist", variant)
684
- ];
685
648
  let coreDir = "";
686
- for (const p of basePaths) {
649
+ for (const p of getCoreDirs(variant)) {
687
650
  if (fs.existsSync(p)) {
688
651
  coreDir = p;
689
652
  break;
@@ -692,15 +655,14 @@ function writeBridgeRuntime(info, options) {
692
655
  if (!coreDir) {
693
656
  return;
694
657
  }
695
- const absoluteOutDir = path.resolve(process.cwd(), outDir, info.name);
658
+ const absoluteOutDir = path.resolve(process.cwd(), outDir, bridgeName);
696
659
  if (!fs.existsSync(absoluteOutDir)) {
697
660
  fs.mkdirSync(absoluteOutDir, { recursive: true });
698
661
  }
699
662
  const extensions = ["js", "mjs"];
700
663
  const replaceContent = JSON.stringify(allowedOrigins).slice(1, -1);
701
- const runtimeName = info.target === "parent" ? "parent-core" : "core";
702
664
  for (const ext of extensions) {
703
- const srcFile = path.join(coreDir, `${runtimeName}.${ext}`);
665
+ const srcFile = path.join(coreDir, `core.${ext}`);
704
666
  if (fs.existsSync(srcFile)) {
705
667
  try {
706
668
  let content = fs.readFileSync(srcFile, "utf-8");