penpal 6.1.0 → 6.2.2

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/README.md CHANGED
@@ -47,6 +47,9 @@ import { connectToChild } from 'penpal';
47
47
 
48
48
  const iframe = document.createElement('iframe');
49
49
  iframe.src = 'http://example.com/iframe.html';
50
+
51
+ // This conditional is not Penpal-specific. It's merely
52
+ // an example of how you can add an iframe to the document.
50
53
  if (
51
54
  document.readyState === 'complete' ||
52
55
  document.readyState === 'interactive'
@@ -58,10 +61,11 @@ if (
58
61
  });
59
62
  }
60
63
 
64
+ // This is where the magic begins.
61
65
  const connection = connectToChild({
62
- // The iframe to which a connection should be made
66
+ // The iframe to which a connection should be made.
63
67
  iframe,
64
- // Methods the parent is exposing to the child
68
+ // Methods the parent is exposing to the child.
65
69
  methods: {
66
70
  add(num1, num2) {
67
71
  return num1 + num2;
@@ -81,13 +85,14 @@ connection.promise.then((child) => {
81
85
  import { connectToParent } from 'penpal';
82
86
 
83
87
  const connection = connectToParent({
84
- // Methods child is exposing to parent
88
+ // Methods child is exposing to parent.
85
89
  methods: {
86
90
  multiply(num1, num2) {
87
91
  return num1 * num2;
88
92
  },
89
93
  divide(num1, num2) {
90
- // Return a promise if the value being returned requires asynchronous processing.
94
+ // Return a promise if the value being
95
+ // returned requires asynchronous processing.
91
96
  return new Promise((resolve) => {
92
97
  setTimeout(() => {
93
98
  resolve(num1 / num2);
@@ -106,47 +111,79 @@ connection.promise.then((parent) => {
106
111
 
107
112
  ### `connectToChild(options: Object) => Object`
108
113
 
109
- **For Penpal to operate correctly, you must ensure that `connectToChild` is called before the iframe has called `connectToParent`.** As shown in the example above, it is safe to set the `src` or `srcdoc` property of the iframe and append the iframe to the document before calling `connectToChild` as long as they are both done in the same [JavaScript event loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop). Alternatively, you can always append the iframe to the document _after_ calling `connectToChild` instead of _before_.
114
+ **For Penpal to operate correctly, you must ensure that `connectToChild` is called before the iframe calls `connectToParent`.** As shown in the example above, it is safe to set the `src` or `srcdoc` property of the iframe and append the iframe to the document before calling `connectToChild` as long as they are both done in the same [JavaScript event loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop). Alternatively, you can always append the iframe to the document _after_ calling `connectToChild` instead of _before_.
110
115
 
111
116
  #### Options
112
117
 
113
- `options.iframe: HTMLIFrameElement` (required) The iframe element to which Penpal should connect. Unless you provide the `childOrigin` option, you will need to have set either the `src` or `srcdoc` property on the iframe prior to calling `connectToChild` so that Penpal can automatically derive the child origin. In addition to regular URLs, [data URIs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) and [file URIs](https://en.wikipedia.org/wiki/File_URI_scheme) are also supported.
118
+ `options.iframe: HTMLIFrameElement` (required)
119
+
120
+ The iframe element to which Penpal should connect. Unless you provide the `childOrigin` option, you will need to have set either the `src` or `srcdoc` property on the iframe prior to calling `connectToChild` so that Penpal can automatically derive the child origin. In addition to regular URLs, [data URIs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) and [file URIs](https://en.wikipedia.org/wiki/File_URI_scheme) are also supported.
121
+
122
+ `options.methods: Object` (optional)
123
+
124
+ An object containing methods which should be exposed for the child iframe to call. The keys of the object are the method names and the values are the functions. Nested objects with function values are recursively included. If a function requires asynchronous processing to determine its return value, make the function immediately return a promise and resolve the promise once the value has been determined.
125
+
126
+ `options.childOrigin: string` (optional)
127
+
128
+ In the vast majority of cases, Penpal can automatically determine the child origin based on the `src` or `srcdoc` property that you have set on the iframe. Communication will automatically be restricted to that origin.
129
+
130
+ In some rare cases, particularly when using the `file://` protocol on various devices, browsers are inconsistent in how they report and handle origins. If you receive an error saying that the parent received a handshake from an unexpected origin, you may need to manually pass the child origin using this option.
131
+
132
+ In other [niche scenarios](https://github.com/Aaronius/penpal/issues/73), you may want the parent to be able to communicate with any child origin. In this case, you can set `childOrigin` to `*`. **This is discouraged.** To illustrate the risk, if a nefarious attacker manages to create a link within the child page that another user can click (for example, if you fail to inadequately escape HTML in a message board comment), and that link navigates the unsuspecting user's iframe to a nefarious URL, then the page at the nefarious URL could start communicating with your parent window.
133
+
134
+ Regardless of how you configure `childOrigin`, communication will always be restricted to only the iframe to which you are connecting.
114
135
 
115
- `options.methods: Object` (optional) An object containing methods which should be exposed for the child iframe to call. The keys of the object are the method names and the values are the functions. Nested objects with function values are recursively included. If a function requires asynchronous processing to determine its return value, make the function immediately return a promise and resolve the promise once the value has been determined.
136
+ `options.timeout: number` (optional)
116
137
 
117
- `options.childOrigin: string` (optional) In the vast majority of cases, Penpal can automatically determine the child origin based on the `src` or `srcdoc` property that you have set on the iframe. Unfortunately, browsers are inconsistent in certain cases, particularly when using the `file://` protocol on various devices. If you receive an error saying that the parent received a handshake from an unexpected origin, you may need to manually pass the child origin using this option.
138
+ The amount of time, in milliseconds, Penpal should wait for the child to respond before rejecting the connection promise. There is no timeout by default.
118
139
 
119
- `options.timeout: number` (optional) The amount of time, in milliseconds, Penpal should wait for the child to respond before rejecting the connection promise. There is no timeout by default.
140
+ `options.debug: boolean` (optional)
120
141
 
121
- `options.debug: boolean` (optional) Enables or disables debug logging. Debug logging is disabled by default.
142
+ Enables or disables debug logging. Debug logging is disabled by default.
122
143
 
123
144
  #### Return value
124
145
 
125
146
  The return value of `connectToChild` is a `connection` object with the following properties:
126
147
 
127
- `connection.promise: Promise` A promise which will be resolved once communication has been established. The promise will be resolved with an object containing the methods which the child has exposed. Note that these aren't actual memory references to the methods the child exposed, but instead proxy methods Penpal has created with the same names and signatures. When one of these methods is called, Penpal will immediately return a promise and then go to work sending a message to the child, calling the actual method within the child with the arguments you have passed, and then sending the return value back to the parent. The promise you received will then be resolved with the return value.
148
+ `connection.promise: Promise`
128
149
 
129
- `connection.destroy: Function` A method that, when called, will disconnect any messaging channels. You may call this even before a connection has been established.
150
+ A promise which will be resolved once communication has been established. The promise will be resolved with an object containing the methods which the child has exposed. Note that these aren't actual memory references to the methods the child exposed, but instead proxy methods Penpal has created with the same names and signatures. When one of these methods is called, Penpal will immediately return a promise and then go to work sending a message to the child, calling the actual method within the child with the arguments you have passed, and then sending the return value back to the parent. The promise you received will then be resolved with the return value.
151
+
152
+ `connection.destroy: Function`
153
+
154
+ A method that, when called, will disconnect any messaging channels. You may call this even before a connection has been established.
130
155
 
131
156
  ### `connectToParent([options: Object]) => Object`
132
157
 
133
158
  #### Options
134
159
 
135
- `options.parentOrigin: string | RegExp` (optional) The origin of the parent window which your iframe will be communicating with. If this is not provided, communication will not be restricted to any particular parent origin resulting in any webpage being able to load your webpage into an iframe and communicate with it.
160
+ `options.parentOrigin: string | RegExp` (optional **but highly recommended!**)
161
+
162
+ The origin of the parent window which your iframe will be communicating with. If this is not provided, communication will not be restricted to any particular parent origin resulting in any webpage being able to load your webpage into an iframe and communicate with it.
163
+
164
+ `options.methods: Object` (optional)
165
+
166
+ An object containing methods which should be exposed for the parent window to call. The keys of the object are the method names and the values are the functions. Nested objects with function values are recursively included. If a function requires asynchronous processing to determine its return value, make the function immediately return a promise and resolve the promise once the value has been determined.
136
167
 
137
- `options.methods: Object` (optional) An object containing methods which should be exposed for the parent window to call. The keys of the object are the method names and the values are the functions. Nested objects with function values are recursively included. If a function requires asynchronous processing to determine its return value, make the function immediately return a promise and resolve the promise once the value has been determined.
168
+ `options.timeout: number` (optional)
138
169
 
139
- `options.timeout: number` (optional) The amount of time, in milliseconds, Penpal should wait for the parent to respond before rejecting the connection promise. There is no timeout by default.
170
+ The amount of time, in milliseconds, Penpal should wait for the parent to respond before rejecting the connection promise. There is no timeout by default.
140
171
 
141
- `options.debug: boolean` (optional) Enables or disables debug logging. Debug logging is disabled by default.
172
+ `options.debug: boolean` (optional)
173
+
174
+ Enables or disables debug logging. Debug logging is disabled by default.
142
175
 
143
176
  #### Return value
144
177
 
145
- The return value of `connectToParent` is a `connection` object with the following property:
178
+ The return value of `connectToParent` is a `connection` object with the following properties:
179
+
180
+ `connection.promise: Promise`
146
181
 
147
- `connection.promise: Promise` A promise which will be resolved once communication has been established. The promise will be resolved with an object containing the methods which the parent has exposed. Note that these aren't actual memory references to the methods the parent exposed, but instead proxy methods Penpal has created with the same names and signatures. When one of these methods is called, Penpal will immediately return a promise and then go to work sending a message to the parent, calling the actual method within the parent with the arguments you have passed, and then sending the return value back to the child. The promise you received will then be resolved with the return value.
182
+ A promise which will be resolved once communication has been established. The promise will be resolved with an object containing the methods which the parent has exposed. Note that these aren't actual memory references to the methods the parent exposed, but instead proxy methods Penpal has created with the same names and signatures. When one of these methods is called, Penpal will immediately return a promise and then go to work sending a message to the parent, calling the actual method within the parent with the arguments you have passed, and then sending the return value back to the child. The promise you received will then be resolved with the return value.
148
183
 
149
- `connection.destroy: Function` A method that, when called, will disconnect any messaging channels. You may call this even before a connection has been established.
184
+ `connection.destroy: Function`
185
+
186
+ A method that, when called, will disconnect any messaging channels. You may call this even before a connection has been established.
150
187
 
151
188
  ## Reconnection
152
189
 
@@ -158,12 +195,17 @@ NOTE: Currently there is no API to notify consumers of a reconnection. If this i
158
195
 
159
196
  Penpal will throw (or reject promises with) errors in certain situations. Each error will have a `code` property which may be used for programmatic decisioning (e.g., do something if the error was due to a connection timing out) along with a `message` describing the problem. Errors may be thrown with the following codes:
160
197
 
161
- - `ConnectionDestroyed`
162
- - This error will be thrown when attempting to call a method on `child` or `parent` objects and the connection was previously destroyed.
163
- - `ConnectionTimeout`
164
- - `connection.promise` will be rejected with this error after the `timeout` duration has elapsed and a connection has not been established.
165
- - `NoIframeSrc`
166
- - This error will be thrown when the iframe passed into `connectToChild` does not have `src` or `srcdoc` set.
198
+ `ConnectionDestroyed`
199
+
200
+ This error will be thrown when attempting to call a method on `child` or `parent` objects and the connection was previously destroyed.
201
+
202
+ `ConnectionTimeout`
203
+
204
+ The promise found at `connection.promise` will be rejected with this error after the `timeout` duration has elapsed and a connection has not been established.
205
+
206
+ `NoIframeSrc`
207
+
208
+ This error will be thrown when the iframe passed into `connectToChild` does not have `src` or `srcdoc` set.
167
209
 
168
210
  For your convenience, these error codes can be imported as follows:
169
211
 
@@ -174,6 +216,43 @@ import { ErrorCode } from 'penpal';
174
216
  // ErrorCode.NoIframeSrc
175
217
  ```
176
218
 
219
+ ## TypeScript
220
+
221
+ When calling `connectToChild` or `connectToParent`, you may pass a generic type argument. This will be used to type the `child` or `parent` object that `connection.promise` is resolved with. This is better explained in code:
222
+
223
+ ```typescript
224
+ import { connectToChild } from 'penpal';
225
+
226
+ // This interace could be imported from a code library
227
+ // that both the parent and child share.
228
+ interface ChildApi {
229
+ multiply(...args: number[]): number;
230
+ }
231
+
232
+ // Supply the interface as a generic argument.
233
+ const connection = connectToChild<ChildApi>({
234
+ iframe: new HTMLIFrameElement(),
235
+ });
236
+
237
+ // The resulting child object will contain properly
238
+ // typed methods.
239
+ const child = await connection.promise;
240
+ // The result variable is typed as a number.
241
+ const result = await child.multiply(1, 3);
242
+ ```
243
+
244
+ The following TypeScript types are also exported as named constants for your use:
245
+
246
+ - `Connection`
247
+ - `Methods`
248
+ - `AsyncMethodReturns`
249
+ - `CallSender`
250
+ - `PenpalError`
251
+
252
+ ## React
253
+
254
+ If you're using Penpal within a React app, please check out [react-penpal](https://github.com/Lunuy/react-penpal).
255
+
177
256
  ## Supported Browsers
178
257
 
179
258
  Penpal is designed to run successfully on the most recent versions of Chrome, Firefox, Safari, and Edge. If you need to support Internet Explorer 11, feel free to use version 3.x of Penpal. See the [3.x README](https://github.com/Aaronius/penpal/tree/3.x) for documentation.
package/dist/penpal.js CHANGED
@@ -45,7 +45,7 @@ var Penpal = (function () {
45
45
  destroy(error) {
46
46
  if (!destroyed) {
47
47
  destroyed = true;
48
- log("".concat(localName, ": Destroying connection"));
48
+ log(`${localName}: Destroying connection`);
49
49
  callbacks.forEach(callback => {
50
50
  callback(error);
51
51
  });
@@ -112,8 +112,8 @@ var Penpal = (function () {
112
112
  // or it won't match the message's event.origin.
113
113
 
114
114
 
115
- const portSuffix = port && port !== DEFAULT_PORT_BY_PROTOCOL[protocol] ? ":".concat(port) : '';
116
- return "".concat(protocol, "//").concat(hostname).concat(portSuffix);
115
+ const portSuffix = port && port !== DEFAULT_PORT_BY_PROTOCOL[protocol] ? `:${port}` : '';
116
+ return `${protocol}//${hostname}${portSuffix}`;
117
117
  });
118
118
 
119
119
  /**
@@ -159,8 +159,8 @@ var Penpal = (function () {
159
159
  return;
160
160
  }
161
161
 
162
- if (event.origin !== originForReceiving) {
163
- log("".concat(localName, " received message from origin ").concat(event.origin, " which did not match expected origin ").concat(originForReceiving));
162
+ if (originForReceiving !== '*' && event.origin !== originForReceiving) {
163
+ log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
164
164
  return;
165
165
  }
166
166
 
@@ -170,11 +170,11 @@ var Penpal = (function () {
170
170
  args,
171
171
  id
172
172
  } = callMessage;
173
- log("".concat(localName, ": Received ").concat(methodName, "() call"));
173
+ log(`${localName}: Received ${methodName}() call`);
174
174
 
175
175
  const createPromiseHandler = resolution => {
176
176
  return returnValue => {
177
- log("".concat(localName, ": Sending ").concat(methodName, "() reply"));
177
+ log(`${localName}: Sending ${methodName}() reply`);
178
178
 
179
179
  if (destroyed) {
180
180
  // It's possible to throw an error here, but it would need to be thrown asynchronously
@@ -182,7 +182,7 @@ var Penpal = (function () {
182
182
  // is merely returning a value from their method and not calling any function
183
183
  // that they could wrap in a try-catch. Even if the consumer were to catch the error,
184
184
  // the value of doing so is questionable. Instead, we'll just log a message.
185
- log("".concat(localName, ": Unable to send ").concat(methodName, "() reply due to destroyed connection"));
185
+ log(`${localName}: Unable to send ${methodName}() reply due to destroyed connection`);
186
186
  return;
187
187
  }
188
188
 
@@ -338,11 +338,11 @@ var Penpal = (function () {
338
338
  originForReceiving
339
339
  } = info;
340
340
  let destroyed = false;
341
- log("".concat(localName, ": Connecting call sender"));
341
+ log(`${localName}: Connecting call sender`);
342
342
 
343
343
  const createMethodProxy = methodName => {
344
344
  return (...args) => {
345
- log("".concat(localName, ": Sending ").concat(methodName, "() call")); // This handles the case where the iframe has been removed from the DOM
345
+ log(`${localName}: Sending ${methodName}() call`); // This handles the case where the iframe has been removed from the DOM
346
346
  // (and therefore its window closed), the consumer has not yet
347
347
  // called destroy(), and the user calls a method exposed by
348
348
  // the remote. We detect the iframe has been removed and force
@@ -367,7 +367,7 @@ var Penpal = (function () {
367
367
  }
368
368
 
369
369
  if (destroyed) {
370
- const error = new Error("Unable to send ".concat(methodName, "() call due ") + "to destroyed connection");
370
+ const error = new Error(`Unable to send ${methodName}() call due ` + `to destroyed connection`);
371
371
  error.code = ErrorCode.ConnectionDestroyed;
372
372
  throw error;
373
373
  }
@@ -380,13 +380,13 @@ var Penpal = (function () {
380
380
  return;
381
381
  }
382
382
 
383
- if (event.origin !== originForReceiving) {
384
- log("".concat(localName, " received message from origin ").concat(event.origin, " which did not match expected origin ").concat(originForReceiving));
383
+ if (originForReceiving !== '*' && event.origin !== originForReceiving) {
384
+ log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
385
385
  return;
386
386
  }
387
387
 
388
388
  const replyMessage = event.data;
389
- log("".concat(localName, ": Received ").concat(methodName, "() reply"));
389
+ log(`${localName}: Received ${methodName}() reply`);
390
390
  local.removeEventListener(NativeEventType.Message, handleMessageEvent);
391
391
  let returnValue = replyMessage.returnValue;
392
392
 
@@ -439,8 +439,8 @@ var Penpal = (function () {
439
439
 
440
440
  const callSender = {};
441
441
  return event => {
442
- if (event.origin !== childOrigin) {
443
- log("Parent: Handshake - Received ACK message from origin ".concat(event.origin, " which did not match expected origin ").concat(childOrigin));
442
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
443
+ log(`Parent: Handshake - Received ACK message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
444
444
  return;
445
445
  }
446
446
 
@@ -481,8 +481,16 @@ var Penpal = (function () {
481
481
 
482
482
  var handleSynMessageFactory = ((log, serializedMethods, childOrigin, originForSending) => {
483
483
  return event => {
484
- if (event.origin !== childOrigin) {
485
- log("Parent: Handshake - Received SYN message from origin ".concat(event.origin, " which did not match expected origin ").concat(childOrigin));
484
+ // Under specific timing circumstances, we can receive an event
485
+ // whose source is null. This seems to happen when the child iframe is
486
+ // removed from the DOM about the same time it has sent the SYN event.
487
+ // https://github.com/Aaronius/penpal/issues/85
488
+ if (!event.source) {
489
+ return;
490
+ }
491
+
492
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
493
+ log(`Parent: Handshake - Received SYN message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
486
494
  return;
487
495
  }
488
496
 
@@ -532,7 +540,7 @@ var Penpal = (function () {
532
540
 
533
541
  if (timeout !== undefined) {
534
542
  timeoutId = window.setTimeout(() => {
535
- const error = new Error("Connection timed out after ".concat(timeout, "ms"));
543
+ const error = new Error(`Connection timed out after ${timeout}ms`);
536
544
  error.code = ErrorCode.ConnectionTimeout;
537
545
  callback(error);
538
546
  }, timeout);
@@ -642,7 +650,7 @@ var Penpal = (function () {
642
650
  let originQualifies = parentOrigin instanceof RegExp ? parentOrigin.test(event.origin) : parentOrigin === '*' || parentOrigin === event.origin;
643
651
 
644
652
  if (!originQualifies) {
645
- log("Child: Handshake - Received SYN-ACK from origin ".concat(event.origin, " which did not match expected origin ").concat(parentOrigin));
653
+ log(`Child: Handshake - Received SYN-ACK from origin ${event.origin} which did not match expected origin ${parentOrigin}`);
646
654
  return;
647
655
  }
648
656
 
@@ -1 +1 @@
1
- var Penpal=function(){"use strict";var e;(function(e){e["Call"]="call";e["Reply"]="reply";e["Syn"]="syn";e["SynAck"]="synAck";e["Ack"]="ack"})(e||(e={}));var n;(function(e){e["Fulfilled"]="fulfilled";e["Rejected"]="rejected"})(n||(n={}));var t;(function(e){e["ConnectionDestroyed"]="ConnectionDestroyed";e["ConnectionTimeout"]="ConnectionTimeout";e["NoIframeSrc"]="NoIframeSrc"})(t||(t={}));var o;(function(e){e["DataCloneError"]="DataCloneError"})(o||(o={}));var r;(function(e){e["Message"]="message"})(r||(r={}));var c=(e,n)=>{const t=[];let o=false;return{destroy(r){if(!o){o=true;n("".concat(e,": Destroying connection"));t.forEach(e=>{e(r)})}},onDestroy(e){o?e():t.push(e)}}};var s=e=>(...n)=>{if(e){console.log("[Penpal]",...n)}};const i={"http:":"80","https:":"443"};const a=/^(https?:)?\/\/([^/:]+)?(:(\d+))?/;const d=["file:","data:"];var l=e=>{if(e&&d.find(n=>e.startsWith(n))){return"null"}const n=document.location;const t=a.exec(e);let o;let r;let c;if(t){o=t[1]?t[1]:n.protocol;r=t[2];c=t[4]}else{o=n.protocol;r=n.hostname;c=n.port}const s=c&&c!==i[o]?":".concat(c):"";return"".concat(o,"//").concat(r).concat(s)};const u=({name:e,message:n,stack:t})=>({name:e,message:n,stack:t});const f=e=>{const n=new Error;Object.keys(e).forEach(t=>n[t]=e[t]);return n};var g=(t,c,s)=>{const{localName:i,local:a,remote:d,originForSending:l,originForReceiving:f}=t;let g=false;const m=t=>{if(t.source!==d||t.data.penpal!==e.Call){return}if(t.origin!==f){s("".concat(i," received message from origin ").concat(t.origin," which did not match expected origin ").concat(f));return}const r=t.data;const{methodName:a,args:m,id:p}=r;s("".concat(i,": Received ").concat(a,"() call"));const h=t=>r=>{s("".concat(i,": Sending ").concat(a,"() reply"));if(g){s("".concat(i,": Unable to send ").concat(a,"() reply due to destroyed connection"));return}const c={penpal:e.Reply,id:p,resolution:t,returnValue:r};if(t===n.Rejected&&r instanceof Error){c.returnValue=u(r);c.returnValueIsError=true}try{d.postMessage(c,l)}catch(t){if(t.name===o.DataCloneError){const o={penpal:e.Reply,id:p,resolution:n.Rejected,returnValue:u(t),returnValueIsError:true};d.postMessage(o,l)}throw t}};new Promise(e=>e(c[a].apply(c,m))).then(h(n.Fulfilled),h(n.Rejected))};a.addEventListener(r.Message,m);return()=>{g=true;a.removeEventListener(r.Message,m)}};let m=0;var p=()=>++m;const h=".";const v=e=>e?e.split(h):[];const y=e=>e.join(h);const w=(e,n)=>{const t=v(n||"");t.push(e);return y(t)};const C=(e,n,t)=>{const o=v(n);o.reduce((e,n,r)=>{if(typeof e[n]==="undefined"){e[n]={}}if(r===o.length-1){e[n]=t}return e[n]},e);return e};const E=(e,n)=>{const t={};Object.keys(e).forEach(o=>{const r=e[o];const c=w(o,n);if(typeof r==="object"){Object.assign(t,E(r,c))}if(typeof r==="function"){t[c]=r}});return t};const k=e=>{const n={};for(const t in e){C(n,t,e[t])}return n};var R=(o,c,s,i,a)=>{const{localName:d,local:l,remote:u,originForSending:g,originForReceiving:m}=c;let h=false;a("".concat(d,": Connecting call sender"));const v=o=>(...c)=>{a("".concat(d,": Sending ").concat(o,"() call"));let s;try{if(u.closed){s=true}}catch(e){s=true}if(s){i()}if(h){const e=new Error("Unable to send ".concat(o,"() call due ")+"to destroyed connection");e.code=t.ConnectionDestroyed;throw e}return new Promise((t,s)=>{const i=p();const h=c=>{if(c.source!==u||c.data.penpal!==e.Reply||c.data.id!==i){return}if(c.origin!==m){a("".concat(d," received message from origin ").concat(c.origin," which did not match expected origin ").concat(m));return}const g=c.data;a("".concat(d,": Received ").concat(o,"() reply"));l.removeEventListener(r.Message,h);let p=g.returnValue;if(g.returnValueIsError){p=f(p)}(g.resolution===n.Fulfilled?t:s)(p)};l.addEventListener(r.Message,h);const v={penpal:e.Call,id:i,methodName:o,args:c};u.postMessage(v,g)})};const y=s.reduce((e,n)=>{e[n]=v(n);return e},{});Object.assign(o,k(y));return()=>{h=true}};var S=(e,n,t,o,r)=>{const{destroy:c,onDestroy:s}=o;let i;let a;const d={};return o=>{if(o.origin!==n){r("Parent: Handshake - Received ACK message from origin ".concat(o.origin," which did not match expected origin ").concat(n));return}r("Parent: Handshake - Received ACK");const l={localName:"Parent",local:window,remote:o.source,originForSending:t,originForReceiving:n};if(i){i()}i=g(l,e,r);s(i);if(a){a.forEach(e=>{delete d[e]})}a=o.data.methodNames;const u=R(d,l,a,c,r);s(u);return d}};var N=(n,t,o,r)=>c=>{if(c.origin!==o){n("Parent: Handshake - Received SYN message from origin ".concat(c.origin," which did not match expected origin ").concat(o));return}n("Parent: Handshake - Received SYN, responding with SYN-ACK");const s={penpal:e.SynAck,methodNames:Object.keys(t)};c.source.postMessage(s,r)};const M=6e4;var A=(e,n)=>{const{destroy:t,onDestroy:o}=n;const r=setInterval(()=>{if(!e.isConnected){clearInterval(r);t()}},M);o(()=>{clearInterval(r)})};var P=(e,n)=>{let o;if(e!==undefined){o=window.setTimeout(()=>{const o=new Error("Connection timed out after ".concat(e,"ms"));o.code=t.ConnectionTimeout;n(o)},e)}return()=>{clearTimeout(o)}};var j=e=>{if(!e.src&&!e.srcdoc){const e=new Error("Iframe must have src or srcdoc property defined.");e.code=t.NoIframeSrc;throw e}};var D=n=>{let{iframe:t,methods:o={},childOrigin:i,timeout:a,debug:d=false}=n;const u=s(d);const f=c("Parent",u);const{onDestroy:g,destroy:m}=f;if(!i){j(t);i=l(t.src)}const p=i==="null"?"*":i;const h=E(o);const v=N(u,h,i,p);const y=S(h,i,p,f,u);const w=new Promise((n,o)=>{const c=P(a,m);const s=o=>{if(o.source!==t.contentWindow||!o.data){return}if(o.data.penpal===e.Syn){v(o);return}if(o.data.penpal===e.Ack){const e=y(o);if(e){c();n(e)}return}};window.addEventListener(r.Message,s);u("Parent: Awaiting handshake");A(t,f);g(e=>{window.removeEventListener(r.Message,s);if(e){o(e)}})});return{promise:w,destroy(){m()}}};var b=(n,t,o,r)=>{const{destroy:c,onDestroy:s}=o;return o=>{let i=n instanceof RegExp?n.test(o.origin):n==="*"||n===o.origin;if(!i){r("Child: Handshake - Received SYN-ACK from origin ".concat(o.origin," which did not match expected origin ").concat(n));return}r("Child: Handshake - Received SYN-ACK, responding with ACK");const a=o.origin==="null"?"*":o.origin;const d={penpal:e.Ack,methodNames:Object.keys(t)};window.parent.postMessage(d,a);const l={localName:"Child",local:window,remote:window.parent,originForSending:a,originForReceiving:o.origin};const u=g(l,t,r);s(u);const f={};const m=R(f,l,o.data.methodNames,c,r);s(m);return f}};const F=()=>{try{clearTimeout()}catch(e){return false}return true};var I=(n={})=>{const{parentOrigin:t="*",methods:o={},timeout:i,debug:a=false}=n;const d=s(a);const l=c("Child",d);const{destroy:u,onDestroy:f}=l;const g=E(o);const m=b(t,g,l,d);const p=()=>{d("Child: Handshake - Sending SYN");const n={penpal:e.Syn};const o=t instanceof RegExp?"*":t;window.parent.postMessage(n,o)};const h=new Promise((n,t)=>{const o=P(i,u);const c=t=>{if(!F()){return}if(t.source!==parent||!t.data){return}if(t.data.penpal===e.SynAck){const e=m(t);if(e){window.removeEventListener(r.Message,c);o();n(e)}}};window.addEventListener(r.Message,c);p();f(e=>{window.removeEventListener(r.Message,c);if(e){t(e)}})});return{promise:h,destroy(){u()}}};var L={connectToChild:D,connectToParent:I,ErrorCode:t};return L}();
1
+ var Penpal=function(){"use strict";var e;(function(e){e["Call"]="call";e["Reply"]="reply";e["Syn"]="syn";e["SynAck"]="synAck";e["Ack"]="ack"})(e||(e={}));var n;(function(e){e["Fulfilled"]="fulfilled";e["Rejected"]="rejected"})(n||(n={}));var t;(function(e){e["ConnectionDestroyed"]="ConnectionDestroyed";e["ConnectionTimeout"]="ConnectionTimeout";e["NoIframeSrc"]="NoIframeSrc"})(t||(t={}));var o;(function(e){e["DataCloneError"]="DataCloneError"})(o||(o={}));var r;(function(e){e["Message"]="message"})(r||(r={}));var s=(e,n)=>{const t=[];let o=false;return{destroy(r){if(!o){o=true;n(`${e}: Destroying connection`);t.forEach(e=>{e(r)})}},onDestroy(e){o?e():t.push(e)}}};var i=e=>(...n)=>{if(e){console.log("[Penpal]",...n)}};const c={"http:":"80","https:":"443"};const a=/^(https?:)?\/\/([^/:]+)?(:(\d+))?/;const d=["file:","data:"];var l=e=>{if(e&&d.find(n=>e.startsWith(n))){return"null"}const n=document.location;const t=a.exec(e);let o;let r;let s;if(t){o=t[1]?t[1]:n.protocol;r=t[2];s=t[4]}else{o=n.protocol;r=n.hostname;s=n.port}const i=s&&s!==c[o]?`:${s}`:"";return`${o}//${r}${i}`};const u=({name:e,message:n,stack:t})=>({name:e,message:n,stack:t});const f=e=>{const n=new Error;Object.keys(e).forEach(t=>n[t]=e[t]);return n};var g=(t,s,i)=>{const{localName:c,local:a,remote:d,originForSending:l,originForReceiving:f}=t;let g=false;const m=t=>{if(t.source!==d||t.data.penpal!==e.Call){return}if(f!=="*"&&t.origin!==f){i(`${c} received message from origin ${t.origin} which did not match expected origin ${f}`);return}const r=t.data;const{methodName:a,args:m,id:p}=r;i(`${c}: Received ${a}() call`);const h=t=>r=>{i(`${c}: Sending ${a}() reply`);if(g){i(`${c}: Unable to send ${a}() reply due to destroyed connection`);return}const s={penpal:e.Reply,id:p,resolution:t,returnValue:r};if(t===n.Rejected&&r instanceof Error){s.returnValue=u(r);s.returnValueIsError=true}try{d.postMessage(s,l)}catch(t){if(t.name===o.DataCloneError){const o={penpal:e.Reply,id:p,resolution:n.Rejected,returnValue:u(t),returnValueIsError:true};d.postMessage(o,l)}throw t}};new Promise(e=>e(s[a].apply(s,m))).then(h(n.Fulfilled),h(n.Rejected))};a.addEventListener(r.Message,m);return()=>{g=true;a.removeEventListener(r.Message,m)}};let m=0;var p=()=>++m;const h=".";const v=e=>e?e.split(h):[];const y=e=>e.join(h);const w=(e,n)=>{const t=v(n||"");t.push(e);return y(t)};const $=(e,n,t)=>{const o=v(n);o.reduce((e,n,r)=>{if(typeof e[n]==="undefined"){e[n]={}}if(r===o.length-1){e[n]=t}return e[n]},e);return e};const C=(e,n)=>{const t={};Object.keys(e).forEach(o=>{const r=e[o];const s=w(o,n);if(typeof r==="object"){Object.assign(t,C(r,s))}if(typeof r==="function"){t[s]=r}});return t};const E=e=>{const n={};for(const t in e){$(n,t,e[t])}return n};var k=(o,s,i,c,a)=>{const{localName:d,local:l,remote:u,originForSending:g,originForReceiving:m}=s;let h=false;a(`${d}: Connecting call sender`);const v=o=>(...s)=>{a(`${d}: Sending ${o}() call`);let i;try{if(u.closed){i=true}}catch(e){i=true}if(i){c()}if(h){const e=new Error(`Unable to send ${o}() call due `+`to destroyed connection`);e.code=t.ConnectionDestroyed;throw e}return new Promise((t,i)=>{const c=p();const h=s=>{if(s.source!==u||s.data.penpal!==e.Reply||s.data.id!==c){return}if(m!=="*"&&s.origin!==m){a(`${d} received message from origin ${s.origin} which did not match expected origin ${m}`);return}const g=s.data;a(`${d}: Received ${o}() reply`);l.removeEventListener(r.Message,h);let p=g.returnValue;if(g.returnValueIsError){p=f(p)}(g.resolution===n.Fulfilled?t:i)(p)};l.addEventListener(r.Message,h);const v={penpal:e.Call,id:c,methodName:o,args:s};u.postMessage(v,g)})};const y=i.reduce((e,n)=>{e[n]=v(n);return e},{});Object.assign(o,E(y));return()=>{h=true}};var R=(e,n,t,o,r)=>{const{destroy:s,onDestroy:i}=o;let c;let a;const d={};return o=>{if(n!=="*"&&o.origin!==n){r(`Parent: Handshake - Received ACK message from origin ${o.origin} which did not match expected origin ${n}`);return}r("Parent: Handshake - Received ACK");const l={localName:"Parent",local:window,remote:o.source,originForSending:t,originForReceiving:n};if(c){c()}c=g(l,e,r);i(c);if(a){a.forEach(e=>{delete d[e]})}a=o.data.methodNames;const u=k(d,l,a,s,r);i(u);return d}};var S=(n,t,o,r)=>s=>{if(!s.source){return}if(o!=="*"&&s.origin!==o){n(`Parent: Handshake - Received SYN message from origin ${s.origin} which did not match expected origin ${o}`);return}n("Parent: Handshake - Received SYN, responding with SYN-ACK");const i={penpal:e.SynAck,methodNames:Object.keys(t)};s.source.postMessage(i,r)};const N=6e4;var M=(e,n)=>{const{destroy:t,onDestroy:o}=n;const r=setInterval(()=>{if(!e.isConnected){clearInterval(r);t()}},N);o(()=>{clearInterval(r)})};var A=(e,n)=>{let o;if(e!==undefined){o=window.setTimeout(()=>{const o=new Error(`Connection timed out after ${e}ms`);o.code=t.ConnectionTimeout;n(o)},e)}return()=>{clearTimeout(o)}};var P=e=>{if(!e.src&&!e.srcdoc){const e=new Error("Iframe must have src or srcdoc property defined.");e.code=t.NoIframeSrc;throw e}};var j=n=>{let{iframe:t,methods:o={},childOrigin:c,timeout:a,debug:d=false}=n;const u=i(d);const f=s("Parent",u);const{onDestroy:g,destroy:m}=f;if(!c){P(t);c=l(t.src)}const p=c==="null"?"*":c;const h=C(o);const v=S(u,h,c,p);const y=R(h,c,p,f,u);const w=new Promise((n,o)=>{const s=A(a,m);const i=o=>{if(o.source!==t.contentWindow||!o.data){return}if(o.data.penpal===e.Syn){v(o);return}if(o.data.penpal===e.Ack){const e=y(o);if(e){s();n(e)}return}};window.addEventListener(r.Message,i);u("Parent: Awaiting handshake");M(t,f);g(e=>{window.removeEventListener(r.Message,i);if(e){o(e)}})});return{promise:w,destroy(){m()}}};var D=(n,t,o,r)=>{const{destroy:s,onDestroy:i}=o;return o=>{let c=n instanceof RegExp?n.test(o.origin):n==="*"||n===o.origin;if(!c){r(`Child: Handshake - Received SYN-ACK from origin ${o.origin} which did not match expected origin ${n}`);return}r("Child: Handshake - Received SYN-ACK, responding with ACK");const a=o.origin==="null"?"*":o.origin;const d={penpal:e.Ack,methodNames:Object.keys(t)};window.parent.postMessage(d,a);const l={localName:"Child",local:window,remote:window.parent,originForSending:a,originForReceiving:o.origin};const u=g(l,t,r);i(u);const f={};const m=k(f,l,o.data.methodNames,s,r);i(m);return f}};const b=()=>{try{clearTimeout()}catch(e){return false}return true};var F=(n={})=>{const{parentOrigin:t="*",methods:o={},timeout:c,debug:a=false}=n;const d=i(a);const l=s("Child",d);const{destroy:u,onDestroy:f}=l;const g=C(o);const m=D(t,g,l,d);const p=()=>{d("Child: Handshake - Sending SYN");const n={penpal:e.Syn};const o=t instanceof RegExp?"*":t;window.parent.postMessage(n,o)};const h=new Promise((n,t)=>{const o=A(c,u);const s=t=>{if(!b()){return}if(t.source!==parent||!t.data){return}if(t.data.penpal===e.SynAck){const e=m(t);if(e){window.removeEventListener(r.Message,s);o();n(e)}}};window.addEventListener(r.Message,s);p();f(e=>{window.removeEventListener(r.Message,s);if(e){t(e)}})});return{promise:h,destroy(){u()}}};var I={connectToChild:j,connectToParent:F,ErrorCode:t};return I}();
@@ -1 +1 @@
1
- {"version":3,"sources":["dist/penpal.js"],"names":["Penpal","MessageType","Resolution","ErrorCode","NativeErrorName","NativeEventType","createDestructor","localName","log","callbacks","destroyed","[object Object]","error","concat","forEach","callback","push","createLogger","debug","args","console","DEFAULT_PORT_BY_PROTOCOL","http:","https:","URL_REGEX","opaqueOriginSchemes","getOriginFromSrc","src","find","scheme","startsWith","location","document","regexResult","exec","protocol","hostname","port","portSuffix","serializeError","name","message","stack","deserializeError","obj","deserializedError","Error","Object","keys","key","connectCallReceiver","info","serializedMethods","local","remote","originForSending","originForReceiving","handleMessageEvent","event","source","data","penpal","Call","origin","callMessage","methodName","id","createPromiseHandler","resolution","returnValue","Reply","Rejected","returnValueIsError","postMessage","err","DataCloneError","errorReplyMessage","Promise","resolve","apply","then","Fulfilled","addEventListener","Message","removeEventListener","generateId","KEY_PATH_DELIMITER","keyPathToSegments","keyPath","split","segmentsToKeyPath","segments","join","createKeyPath","prefix","setAtKeyPath","subject","value","reduce","prevSubject","idx","length","serializeMethods","methods","flattenedMethods","assign","deserializeMethods","connectCallSender","callSender","methodKeyPaths","destroyConnection","createMethodProxy","iframeRemoved","closed","e","code","ConnectionDestroyed","reject","replyMessage","api","handleAckMessageFactory","childOrigin","destructor","destroy","onDestroy","destroyCallReceiver","receiverMethodNames","window","receiverMethodName","methodNames","destroyCallSender","handleSynMessageFactory","synAckMessage","SynAck","CHECK_IFRAME_IN_DOC_INTERVAL","monitorIframeRemoval","iframe","checkIframeInDocIntervalId","setInterval","isConnected","clearInterval","startConnectionTimeout","timeout","timeoutId","undefined","setTimeout","ConnectionTimeout","clearTimeout","validateIframeHasSrcOrSrcDoc","srcdoc","NoIframeSrc","connectToChild","options","handleSynMessage","handleAckMessage","promise","stopConnectionTimeout","handleMessage","contentWindow","Syn","Ack","handleSynAckMessageFactory","parentOrigin","originQualifies","RegExp","test","ackMessage","parent","areGlobalsAccessible","connectToParent","handleSynAckMessage","sendSynMessage","synMessage","parentOriginForSyn","indexForBundle"],"mappings":"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"}
1
+ {"version":3,"sources":["dist/penpal.js"],"names":["Penpal","MessageType","Resolution","ErrorCode","NativeErrorName","NativeEventType","createDestructor","localName","log","callbacks","destroyed","[object Object]","error","forEach","callback","push","createLogger","debug","args","console","DEFAULT_PORT_BY_PROTOCOL","http:","https:","URL_REGEX","opaqueOriginSchemes","getOriginFromSrc","src","find","scheme","startsWith","location","document","regexResult","exec","protocol","hostname","port","portSuffix","serializeError","name","message","stack","deserializeError","obj","deserializedError","Error","Object","keys","key","connectCallReceiver","info","serializedMethods","local","remote","originForSending","originForReceiving","handleMessageEvent","event","source","data","penpal","Call","origin","callMessage","methodName","id","createPromiseHandler","resolution","returnValue","Reply","Rejected","returnValueIsError","postMessage","err","DataCloneError","errorReplyMessage","Promise","resolve","apply","then","Fulfilled","addEventListener","Message","removeEventListener","generateId","KEY_PATH_DELIMITER","keyPathToSegments","keyPath","split","segmentsToKeyPath","segments","join","createKeyPath","prefix","setAtKeyPath","subject","value","reduce","prevSubject","idx","length","serializeMethods","methods","flattenedMethods","assign","deserializeMethods","connectCallSender","callSender","methodKeyPaths","destroyConnection","createMethodProxy","iframeRemoved","closed","e","code","ConnectionDestroyed","reject","replyMessage","api","handleAckMessageFactory","childOrigin","destructor","destroy","onDestroy","destroyCallReceiver","receiverMethodNames","window","receiverMethodName","methodNames","destroyCallSender","handleSynMessageFactory","synAckMessage","SynAck","CHECK_IFRAME_IN_DOC_INTERVAL","monitorIframeRemoval","iframe","checkIframeInDocIntervalId","setInterval","isConnected","clearInterval","startConnectionTimeout","timeout","timeoutId","undefined","setTimeout","ConnectionTimeout","clearTimeout","validateIframeHasSrcOrSrcDoc","srcdoc","NoIframeSrc","connectToChild","options","handleSynMessage","handleAckMessage","promise","stopConnectionTimeout","handleMessage","contentWindow","Syn","Ack","handleSynAckMessageFactory","parentOrigin","originQualifies","RegExp","test","ackMessage","parent","areGlobalsAccessible","connectToParent","handleSynAckMessage","sendSynMessage","synMessage","parentOriginForSyn","indexForBundle"],"mappings":"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"}
@@ -25,7 +25,7 @@ var _default = (parentOrigin, serializedMethods, destructor, log) => {
25
25
  let originQualifies = parentOrigin instanceof RegExp ? parentOrigin.test(event.origin) : parentOrigin === '*' || parentOrigin === event.origin;
26
26
 
27
27
  if (!originQualifies) {
28
- log("Child: Handshake - Received SYN-ACK from origin ".concat(event.origin, " which did not match expected origin ").concat(parentOrigin));
28
+ log(`Child: Handshake - Received SYN-ACK from origin ${event.origin} which did not match expected origin ${parentOrigin}`);
29
29
  return;
30
30
  }
31
31
 
@@ -28,8 +28,8 @@ var _default = (info, serializedMethods, log) => {
28
28
  return;
29
29
  }
30
30
 
31
- if (event.origin !== originForReceiving) {
32
- log("".concat(localName, " received message from origin ").concat(event.origin, " which did not match expected origin ").concat(originForReceiving));
31
+ if (originForReceiving !== '*' && event.origin !== originForReceiving) {
32
+ log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
33
33
  return;
34
34
  }
35
35
 
@@ -39,11 +39,11 @@ var _default = (info, serializedMethods, log) => {
39
39
  args,
40
40
  id
41
41
  } = callMessage;
42
- log("".concat(localName, ": Received ").concat(methodName, "() call"));
42
+ log(`${localName}: Received ${methodName}() call`);
43
43
 
44
44
  const createPromiseHandler = resolution => {
45
45
  return returnValue => {
46
- log("".concat(localName, ": Sending ").concat(methodName, "() reply"));
46
+ log(`${localName}: Sending ${methodName}() reply`);
47
47
 
48
48
  if (destroyed) {
49
49
  // It's possible to throw an error here, but it would need to be thrown asynchronously
@@ -51,7 +51,7 @@ var _default = (info, serializedMethods, log) => {
51
51
  // is merely returning a value from their method and not calling any function
52
52
  // that they could wrap in a try-catch. Even if the consumer were to catch the error,
53
53
  // the value of doing so is questionable. Instead, we'll just log a message.
54
- log("".concat(localName, ": Unable to send ").concat(methodName, "() reply due to destroyed connection"));
54
+ log(`${localName}: Unable to send ${methodName}() reply due to destroyed connection`);
55
55
  return;
56
56
  }
57
57
 
@@ -35,11 +35,11 @@ var _default = (callSender, info, methodKeyPaths, destroyConnection, log) => {
35
35
  originForReceiving
36
36
  } = info;
37
37
  let destroyed = false;
38
- log("".concat(localName, ": Connecting call sender"));
38
+ log(`${localName}: Connecting call sender`);
39
39
 
40
40
  const createMethodProxy = methodName => {
41
41
  return (...args) => {
42
- log("".concat(localName, ": Sending ").concat(methodName, "() call")); // This handles the case where the iframe has been removed from the DOM
42
+ log(`${localName}: Sending ${methodName}() call`); // This handles the case where the iframe has been removed from the DOM
43
43
  // (and therefore its window closed), the consumer has not yet
44
44
  // called destroy(), and the user calls a method exposed by
45
45
  // the remote. We detect the iframe has been removed and force
@@ -64,7 +64,7 @@ var _default = (callSender, info, methodKeyPaths, destroyConnection, log) => {
64
64
  }
65
65
 
66
66
  if (destroyed) {
67
- const error = new Error("Unable to send ".concat(methodName, "() call due ") + "to destroyed connection");
67
+ const error = new Error(`Unable to send ${methodName}() call due ` + `to destroyed connection`);
68
68
  error.code = _enums.ErrorCode.ConnectionDestroyed;
69
69
  throw error;
70
70
  }
@@ -77,13 +77,13 @@ var _default = (callSender, info, methodKeyPaths, destroyConnection, log) => {
77
77
  return;
78
78
  }
79
79
 
80
- if (event.origin !== originForReceiving) {
81
- log("".concat(localName, " received message from origin ").concat(event.origin, " which did not match expected origin ").concat(originForReceiving));
80
+ if (originForReceiving !== '*' && event.origin !== originForReceiving) {
81
+ log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
82
82
  return;
83
83
  }
84
84
 
85
85
  const replyMessage = event.data;
86
- log("".concat(localName, ": Received ").concat(methodName, "() reply"));
86
+ log(`${localName}: Received ${methodName}() reply`);
87
87
  local.removeEventListener(_enums.NativeEventType.Message, handleMessageEvent);
88
88
  let returnValue = replyMessage.returnValue;
89
89
 
@@ -12,7 +12,7 @@ var _default = (localName, log) => {
12
12
  destroy(error) {
13
13
  if (!destroyed) {
14
14
  destroyed = true;
15
- log("".concat(localName, ": Destroying connection"));
15
+ log(`${localName}: Destroying connection`);
16
16
  callbacks.forEach(callback => {
17
17
  callback(error);
18
18
  });
@@ -46,8 +46,8 @@ var _default = src => {
46
46
  // or it won't match the message's event.origin.
47
47
 
48
48
 
49
- const portSuffix = port && port !== DEFAULT_PORT_BY_PROTOCOL[protocol] ? ":".concat(port) : '';
50
- return "".concat(protocol, "//").concat(hostname).concat(portSuffix);
49
+ const portSuffix = port && port !== DEFAULT_PORT_BY_PROTOCOL[protocol] ? `:${port}` : '';
50
+ return `${protocol}//${hostname}${portSuffix}`;
51
51
  };
52
52
 
53
53
  exports.default = _default;
@@ -27,8 +27,8 @@ var _default = (serializedMethods, childOrigin, originForSending, destructor, lo
27
27
 
28
28
  const callSender = {};
29
29
  return event => {
30
- if (event.origin !== childOrigin) {
31
- log("Parent: Handshake - Received ACK message from origin ".concat(event.origin, " which did not match expected origin ").concat(childOrigin));
30
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
31
+ log(`Parent: Handshake - Received ACK message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
32
32
  return;
33
33
  }
34
34
 
@@ -12,8 +12,16 @@ var _enums = require("../enums");
12
12
  */
13
13
  var _default = (log, serializedMethods, childOrigin, originForSending) => {
14
14
  return event => {
15
- if (event.origin !== childOrigin) {
16
- log("Parent: Handshake - Received SYN message from origin ".concat(event.origin, " which did not match expected origin ").concat(childOrigin));
15
+ // Under specific timing circumstances, we can receive an event
16
+ // whose source is null. This seems to happen when the child iframe is
17
+ // removed from the DOM about the same time it has sent the SYN event.
18
+ // https://github.com/Aaronius/penpal/issues/85
19
+ if (!event.source) {
20
+ return;
21
+ }
22
+
23
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
24
+ log(`Parent: Handshake - Received SYN message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
17
25
  return;
18
26
  }
19
27
 
@@ -16,7 +16,7 @@ var _default = (timeout, callback) => {
16
16
 
17
17
  if (timeout !== undefined) {
18
18
  timeoutId = window.setTimeout(() => {
19
- const error = new Error("Connection timed out after ".concat(timeout, "ms"));
19
+ const error = new Error(`Connection timed out after ${timeout}ms`);
20
20
  error.code = _enums.ErrorCode.ConnectionTimeout;
21
21
  callback(error);
22
22
  }, timeout);
@@ -11,7 +11,7 @@ export default (info, serializedMethods, log) => {
11
11
  if (event.source !== remote || event.data.penpal !== MessageType.Call) {
12
12
  return;
13
13
  }
14
- if (event.origin !== originForReceiving) {
14
+ if (originForReceiving !== '*' && event.origin !== originForReceiving) {
15
15
  log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
16
16
  return;
17
17
  }
@@ -54,7 +54,8 @@ export default (callSender, info, methodKeyPaths, destroyConnection, log) => {
54
54
  event.data.id !== id) {
55
55
  return;
56
56
  }
57
- if (event.origin !== originForReceiving) {
57
+ if (originForReceiving !== '*' &&
58
+ event.origin !== originForReceiving) {
58
59
  log(`${localName} received message from origin ${event.origin} which did not match expected origin ${originForReceiving}`);
59
60
  return;
60
61
  }
@@ -13,7 +13,7 @@ export default (serializedMethods, childOrigin, originForSending, destructor, lo
13
13
  // latest provided by the child.
14
14
  const callSender = {};
15
15
  return (event) => {
16
- if (event.origin !== childOrigin) {
16
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
17
17
  log(`Parent: Handshake - Received ACK message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
18
18
  return;
19
19
  }
@@ -4,7 +4,14 @@ import { MessageType } from '../enums';
4
4
  */
5
5
  export default (log, serializedMethods, childOrigin, originForSending) => {
6
6
  return (event) => {
7
- if (event.origin !== childOrigin) {
7
+ // Under specific timing circumstances, we can receive an event
8
+ // whose source is null. This seems to happen when the child iframe is
9
+ // removed from the DOM about the same time it has sent the SYN event.
10
+ // https://github.com/Aaronius/penpal/issues/85
11
+ if (!event.source) {
12
+ return;
13
+ }
14
+ if (childOrigin !== '*' && event.origin !== childOrigin) {
8
15
  log(`Parent: Handshake - Received SYN message from origin ${event.origin} which did not match expected origin ${childOrigin}`);
9
16
  return;
10
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "penpal",
3
- "version": "6.1.0",
3
+ "version": "6.2.2",
4
4
  "description": "A promise-based library for communicating with iframes via postMessage.",
5
5
  "author": "Aaron Hardy <aaron@aaronhardy.com>",
6
6
  "license": "MIT",