All Projects → Aaronius → Penpal

Aaronius / Penpal

Licence: mit
A promise-based library for securely communicating with iframes via postMessage.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Penpal

Post Me
📩 Use web Workers and other Windows through a simple Promise API
Stars: ✭ 398 (+102.03%)
Mutual labels:  promise, iframe
Rext
🎈A lightweight (< 5kb gzipped) and Promise-supported HTTP request library, for all browsers.
Stars: ✭ 14 (-92.89%)
Mutual labels:  promise, iframe
Postmate
📭 A powerful, simple, promise-based postMessage library.
Stars: ✭ 1,638 (+731.47%)
Mutual labels:  promise, iframe
Next Session
Simple promise-based session middleware for Next.js, micro, Express, and more
Stars: ✭ 161 (-18.27%)
Mutual labels:  promise
Promise
Promises/A implementation for PHP.
Stars: ✭ 2,078 (+954.82%)
Mutual labels:  promise
Node Instagram
Instagram api client for node that support promises.
Stars: ✭ 185 (-6.09%)
Mutual labels:  promise
Imap Simple
Wrapper over node-imap, providing a simpler api for common use cases
Stars: ✭ 195 (-1.02%)
Mutual labels:  promise
Async Busboy
Promise based multipart form parser for KoaJS
Stars: ✭ 159 (-19.29%)
Mutual labels:  promise
Nedb Promises
A dead-simple promise wrapper for nedb.
Stars: ✭ 190 (-3.55%)
Mutual labels:  promise
Fluture
🦋 Fantasy Land compliant (monadic) alternative to Promises
Stars: ✭ 2,249 (+1041.62%)
Mutual labels:  promise
Apisauce
Axios + standardized errors + request/response transforms.
Stars: ✭ 2,303 (+1069.04%)
Mutual labels:  promise
Kitsu
🦊 A simple, lightweight & framework agnostic JSON:API client
Stars: ✭ 166 (-15.74%)
Mutual labels:  promise
Iframe Resizer React
The official React interface for Iframe-Resizer
Stars: ✭ 183 (-7.11%)
Mutual labels:  iframe
Metasync
Asynchronous Programming Library for JavaScript & Node.js
Stars: ✭ 164 (-16.75%)
Mutual labels:  promise
Ppipe
pipes values through functions, an alternative to using the proposed pipe operator ( |> ) for ES
Stars: ✭ 192 (-2.54%)
Mutual labels:  promise
Ewa
Enhanced Wechat App Development Toolkit (微信小程序增强开发工具)。不同于 wepy 或者 mpvue,是一个轻量级小程序开发框架。支持原生小程序所有功能,无需学习,极易上手。支持转换为百度/字节跳动/QQ小程序。
Stars: ✭ 160 (-18.78%)
Mutual labels:  promise
Filehound
Flexible and fluent interface for searching the file system
Stars: ✭ 190 (-3.55%)
Mutual labels:  promise
Q
A platform-independent promise library for C++, implementing asynchronous continuations.
Stars: ✭ 179 (-9.14%)
Mutual labels:  promise
Scramjet
Simple yet powerful live data computation framework
Stars: ✭ 171 (-13.2%)
Mutual labels:  promise
Cwait
⌛️ Limit number of promises running in parallel
Stars: ✭ 184 (-6.6%)
Mutual labels:  promise

npm version

Upgrading from version 4? See version 5 release notes for details.

See documentation for 4.x
See documentation for 3.x

Penpal

Penpal is a promise-based library for securely communicating with iframes via postMessage. The parent window can call methods exposed by iframes, pass arguments, and receive a return value. Similarly, iframes can call methods exposed by the parent window, pass arguments, and receive a return value. Easy peasy.

This library has no dependencies.

Installation

Using npm

Preferably, you'll be able to use Penpal from npm with a bundler like Webpack, Rollup, or Parcel. If you use npm for client package management, you can install Penpal with:

npm install penpal

Using a CDN

If you don't want to use npm to manage client packages, Penpal also provides a UMD distribution in a dist folder which is hosted on a CDN:

<script src="https://unpkg.com/[email protected]^5/dist/penpal.min.js"></script>

Penpal will then be installed on window.Penpal. window.Penpal will contain the following properties:

Penpal.connectToChild
Penpal.connectToParent
Penpal.ErrorCode.ConnectionDestroyed
Penpal.ErrorCode.ConnectionTimeout
Penpal.ErrorCode.NotInIframe
Penpal.ErrorCode.NoIframeSrc

Usage is similar to if you were using a bundler, which is documented below, but instead of importing each module, you would access it on the Penpal global instead.

Usage

Parent Window

import { connectToChild } from 'penpal';

const iframe = document.createElement('iframe');
iframe.src = 'http://example.com/iframe.html';
if (
  document.readyState === 'complete' ||
  document.readyState === 'interactive'
) {
  document.body.appendChild(iframe);
} else {
  document.addEventListener('DOMContentLoaded', () => {
    document.body.appendChild(iframe);
  });
}

const connection = connectToChild({
  // The iframe to which a connection should be made
  iframe,
  // Methods the parent is exposing to the child
  methods: {
    add(num1, num2) {
      return num1 + num2;
    },
  },
});

connection.promise.then((child) => {
  child.multiply(2, 6).then((total) => console.log(total));
  child.divide(12, 4).then((total) => console.log(total));
});

Child Iframe

import { connectToParent } from 'penpal';

const connection = connectToParent({
  // Methods child is exposing to parent
  methods: {
    multiply(num1, num2) {
      return num1 * num2;
    },
    divide(num1, num2) {
      // Return a promise if the value being returned requires asynchronous processing.
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(num1 / num2);
        }, 1000);
      });
    },
  },
});

connection.promise.then((parent) => {
  parent.add(3, 1).then((total) => console.log(total));
});

API

connectToChild(options: Object) => Object

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. Alternatively, you can always append the iframe to the document after calling connectToChild instead of before.

Options

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 and file URIs are also supported.

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. 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.

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 hanshake from an unexpected origin, you may need to manually pass the child origin using this option.

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.

options.debug: boolean (optional) Enables or disables debug logging. Debug logging is disabled by default.

Return value

The return value of connectToChild is a connection object with the following properties:

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.

connection.destroy: Function A method that, when called, will disconnect any messaging channels. You may call this even before a connection has been established.

connectToParent([options: Object]) => Object

Options

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.

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. 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.

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.

options.debug: boolean (optional) Enables or disables debug logging. Debug logging is disabled by default.

Return value

The return value of connectToParent is a connection object with the following property:

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.

connection.destroy: Function A method that, when called, will disconnect any messaging channels. You may call this even before a connection has been established.

Reconnection

If the child iframe attempts to reconnect with the parent, the parent will accept the new connection. This could happen, for example, if a user refreshes the child iframe or navigates within the iframe to a different page that also uses Penpal. In this case, the child object the parent received when the initial connection was established will be updated with the new methods provided by the child iframe.

NOTE: Currently there is no API to notify consumers of a reconnection. If this is important for you, please provide feedback on this issue with how you would like to see the API designed.

Errors

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:

  • ConnectionDestroyed
    • connection.promise will be rejected with this error if the connection is destroyed (by calling connection.destroy()) while Penpal is attempting to establish the connection.
    • This error will be thrown when attempting to call a method on child or parent objects and the connection was previously destroyed.
  • ConnectionTimeout
    • connection.promise will be rejected with this error after the timeout duration has elapsed and a connection has not been established.
  • NotInIframe
    • This error will be thrown when attempting to call connectToParent() from outside of an iframe context.
  • NoIframeSrc
    • This error will be thrown when the iframe passed into connectToChild does not have src or srcdoc set.

For your convenience, these error codes can be imported as follows:

import { ErrorCode } from 'penpal';
// ErrorCode.ConnectionDestroyed
// ErrorCode.ConnectionTimeout
// ErrorCode.NotInIframe
// ErrorCode.NoIframeSrc

Supported Browsers

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 for documentation.

Penpal has also been reported to work within Ionic projects on iOS and Android devices.

React Support

To implement Penpal within React applications more easily, check out React-Penpal.

Cypress Support

When calling connectToParent, Penpal checks to see if it is running inside an iframe and, if not, throws a NotInIframe error to make you aware of the problem. When running in Cypress, Cypress by default attempts to "modify obstructive code". In other words, if any JavaScript attempts to perform framebusting, Cypress tries to modify the code since such techniques prevent Cypress from working properly. As it turns out, Penpal's check to see if it is running inside of an iframe is not performing framebusting, but Cypress sees it as obstrucive code anyway and attempts to modify it, which actually breaks testing with Cypress + Penpal entirely.

To work around this issue, disable Cypress's modification of obstructive code by setting modifyObstructiveCode to false within your cypress.json file. If you find you must have modifyObstructiveCode enabled for other reasons, please comment on this issue with details about your situation.

Inspiration

This library is inspired by:

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].