npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ekolabs/iframily

v1.0.3

Published

postMessage made simple & safe

Downloads

383

Readme

Iframily - postMessage made simple & safe

Iframily simplifies working and establishing communication between frames.

It provides a simpler API than postMessage, which includes Promise-based responses, message queuing, and holding on to messages until both frames are ready to talk.

This is how it works:

  1. Create iframilies in the parent and child frame.
  2. If a parent id and child id match, they will pair.
  3. Send messages between paired iframilies.

With vanilla postMessage:

postMessage

With Iframily:

Iframily

By the team from

Table of Contents

Features

What makes it special

Iframily pushes you to be more responsible with your frame security by keeping it front and center. You'll need to explicitly specify the allowed origin for communication and the sender's origin for verification, both on the parent and child frames. See more on initParent() / initChild() API.

What makes it awesome

  • Enforces security best practices: Iframily prevents you from accidentally setting too permissive configuration, making you less vulnerable to exploits.
  • Long-lived two-way communication between frames. While other libraries treat messages separately, Iframily enables you to easily respond to incoming messages and maintain the communication chain, keeping track of messages and their responses to allow for more complex communications.
  • Each frame connection is named and identified, allowing for continuous communication even when a frame redirects or reloads.
  • Fast and intuitive promise-based API (supports async responses).
  • Discrete handlers can be defined for specific frames or modules in frames, allowing true separation of concerns and code between the different frames and their uses.
  • Unlike other libraries, you don’t need to change how you initialize your iframes. Iframily works out of the box with any iframe. Just give it a frame identifier and let it do its thing.
  • Message queue until paring completed so messages don’t get lost, even if a frame page hasn’t completed loading yet.
  • Zero dependencies.
  • Unit + battle tested

Examples

Invasion of the Frame Snatchers

Demonstrates a simple usage of Iframily to communicate between a parent and child frame through an interactive, sweet father-son dialogue about world domination.

Text Chat Madness

Demonstrates usage of Iframily to communicate between a parent frame and multiple child frames through interactive conversations in a family of five. How will mom handle all these questions? You decide!

Crazy Tetris

A novel (and somewhat strange) reimplementation of the classic Tetris using Iframily! Each frame runs its own self-contained Tetris instance. The twist? Instead of moving the pieces, the player moves the frames themselves to align the pieces and allow them to flow freely between frames.

See the repo's examples/ directory for the source code.

Installation

npm i @ekolabs/iframily --save

ES6

import Iframily from '@ekolabs/iframily';

CommonJS

const Iframily = require('@ekolabs/iframily');

You can also add the library via script tag and use window.Iframily, like so:

<!-- latest -->
<script src="https://unpkg.com/@ekolabs/iframily"></script>

<!-- specific version (for example: 1.0.0) -->
<script src="https://unpkg.com/@ekolabs/[email protected]"></script>

API

--- Iframily singleton ---

Iframily is a singleton and will allow you to initialize parent/child iframily instances.

🔵 Iframily.initParent(id, targetOrigin, msgHandler, options) -> iframily instance

🔵 Iframily.initChild(id, targetOrigin, msgHandler, options) -> iframily instance

Creates a parent/child iframily instance respectively (to be used in the parent/child frame) and returns it, if successful.

| Param | Type | Description | | :-------------: |:--------------:| :------------| | id | string | A unique id to identify this iframily instance, this is used in order to match parent and child iframilies. Will abort and log an error if the id already exists in the current frame. | | targetOrigin | string | The URI to use as the target origin for the postMessage call and for validating the sender origin on incoming messages, for example: https://subdomain.domain.com. For security concerns this argument is mandatory, see link for more info. If both frames our on the same origin, you can use window.location.origin as the value. Passing "*" (wildcard) is not supported, if you are 100% certain that you want to allow messages to be received and handled by everyone, you can pass "DANGEROUSLY_SET_WILDCARD" instead. | | msgHandler | function | Optional - A handler for incoming messages from the paired iframily in the parent/child frame. The msgHandler can return back a response value or a promise that will be resolved/rejected with a response value. | | options | object | Optional - Additional options, see possible options below: | | options.onPairedHandler | function | Optional - A handler that will be invoked upon pairing. | | options.onDisposedHandler | function | Optional - A handler that will be invoked when the instance is disposed. |

🔵 Iframily.isIframilyMessage(event) -> boolean

If you manually listen to messages using the window "message" event you will also receive internal iframily messages. This method will return true for this events so you can easily identify them.

window.addEventListener('message', receiveMessage);

function receiveMessage(event) {
    // Ignore Iframily messages.
    if (Iframily.isIframilyMessage(event)) {
        return;
    }

    // Handle other messages below:
    // ...
}

--- iframily instance ---

The iframily instance is the object returned when initializing a new iframily using the initParent() or initChild() methods.

🟢 f.sendMessage(msg) -> Promise

| Param | Type | Description | | :-------------: |:--------------:| :------------| | msg | serializable | The message to be sent, can be any serializable data (see structured clone algorithm).

Returns a promise that will be resolved with the response value from the receiving iframily instance message handler. The promise will be rejected if the promised returned by the receiving iframily instance rejects.

If the receiving iframily instance did not return an explicit response value in its message handler, the promise will be resolved with undefined.

🟢 f.dispose()

Dispose of the iframily instance, making it obsolete.

  • You cannot reuse a disposed instance, you can however create a new instance with the same id.
  • Any iframilies paired with this instance will still be able to keep sending messages to the disposed instance but the messages will be ignored by the disposed target.

This method is useful when you have a parent frame which recreates the same child frame and you want to use the same id for the iframilies.

🟢 f.isDisposed -> boolean (read only)

Returns true if this iframily instance has been disposed.

🟢 f.id -> string (read only)

Returns the id that this iframily was initialized with.

Usage example

// -------------------------
// In the parent frame.
// -------------------------
const Iframily = require('@ekolabs/iframily');

let msgHandler = function(msg) {
    console.log('parent got message:', msg);
};

let iframilyParent = Iframily.initParent('myUniqueId', window.location.origin, msgHandler);

iframilyParent.sendMessage('do something').then((response) => {
    console.log('parent got response:', response);
});

iframilyParent.sendMessage('do something async').then((response) => {
    console.log('parent got async response:', response);
});
// -------------------------
// In the child frame.
// -------------------------
const Iframily = require('@ekolabs/iframily');

let msgHandler = function(msg) {
    console.log('child got message:', msg);

    if (msg === 'do something') {
        return 'OK! done!';
    } else if (msg === 'do something async') {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('OK! done async!');
            }, 1000);
        });
    }
};

let iframilyChild = Iframily.initChild('myUniqueId', window.location.origin, msgHandler);

iframilyChild.sendMessage({ text: 'fancy...' });
  • Your unique id (myUniqueId in the example) should match between parent and child.

Notes

  • You can create multiple iframilies in each frame but the unique ids cannot be used more than once per frame (unless the previous one has been disposed).
  • Parent can pair with one child only and vice versa (due to previous note).
  • Specifying "targetOrigin" as regex is not supported mostly to avoid "dot" unescaping security vulnerability.
  • Designed for modern browsers (IE not supported).

Contributing

  • npm run dev - builds unuglified bundle and watches for changes.
  • npm run playground - launch a simple page with a parent and child frame iframilies to manually test out stuff.
  • Please make all pull requests against the develop branch.
  • Please update/add tests coverage.
  • Pay attention to linting (they will fail the production bundle build).
  • npm run test - run tests.
    • npm run test-debug-mac or npm run test-debug-win for debugging the tests.
    • Tests run against the built bundle, so make sure your changes are built before running.
    • Tests require a modification in your hosts file (see note below).

Running tests require node >=10 and modifying your hosts file like so:

# iframily
127.0.0.1   sub1.domain1iframily.com
127.0.0.1   sub2.domain2iframily.com

When your done developing, make sure to run the production build via npm run build so the correct bundle will be committed to the dist folder.