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 🙏

© 2026 – Pkg Stats / Ryan Hefner

post-robot

v12.2.1

Published

Cross-window messaging over postMessage: send a request to a window, get a response, hand functions, promises and windows across and keep calling them.

Readme

post-robot

Cross-window messaging over postMessage: send a request to another window, iframe or popup and get a response; hand functions, promises and windows across and keep using them from the other side.

npm install post-robot
import { on, send } from 'post-robot';

// In the child
on('getUser', ({ data }) => fetchUser(data.id));

// In the parent
const { data: user } = await send(childFrame, 'getUser', { id: '123' });

ES modules, TypeScript types included, ES2019 syntax. For current browsers (Chrome, Firefox, Safari, Edge from 2024 on): the floor is the four APIs sandestin needs, FinalizationRegistry, WeakRef, AbortSignal.any and crypto.randomUUID, and post-robot adds nothing above it. A dist/post-robot.min.js bundle is included for pages that load it with a script tag, as window.postRobot.

Sending and receiving

send(window, name, data?, options?) posts a request and resolves with { source, origin, data } once the other side's handler has run. Before the first message to a window post-robot waits for it to say hello (every window running post-robot does, to its opener or parent), so a request is never fired into a frame that has not loaded yet. Every request is acknowledged on arrival and answered when its handler settles; no acknowledgement within two seconds (ten for a window already heard from) rejects with "no ack", a closed window rejects at once, and options.timeout bounds the wait for the response itself.

| Option | Does | | --- | --- | | domain | The origin the window must be at: a string, a RegExp, a list of either, or * (the default). A string is also what the message is posted to | | timeout | Milliseconds to wait for the response; -1, the default, waits forever | | fireAndForget | Post it and resolve immediately; no acknowledgement, no response |

on(name, options?, handler) registers the handler for a request name and returns { cancel }. The handler gets { source, origin, data } and whatever it returns, or resolves with, is the response; a throw or rejection is the error the sender's promise rejects with. Registering the same name twice for the same window and domain throws.

| Option | Does | | --- | --- | | window | Only accept the request from this window, or from any of these | | domain | Only accept it from an origin matching this | | errorHandler | Where a handler's error goes, instead of being rethrown |

once(name, options?, handler?) is on for a single request: it resolves with the event and stops listening, and has .cancel().

What crosses

Data crosses by value, through sandestin: objects, arrays, strings, numbers, booleans, null, undefined, dates, regular expressions, cycles, and errors with their name, message, code and stack. Anything else (a Map, a class instance) is passed through as plain data. Three things cross by reference:

  • Functions. The other side gets a function that calls the original where it lives and resolves with its result. It has .fireAndForget(...) for a call that needs no reply. Inside the original, this.source and this.origin are the calling window and its origin. A function handed back to the window it came from is the original again, called directly.
  • Promises. Native promises and ZalgoPromises both cross; the other side gets a promise that settles when the original does.
  • Windows. A window crosses as a ProxyWindow: an object with close, focus, isClosed, getType, setLocation, getName, setName and getInstanceID that act on the real window where it lives, and that becomes the real window again when it turns out to be reachable from the receiving side. That is what lets a parent describe windows to a child before the child exists.

Every function and promise handed out is bound to the origin it was sent to; a call for it from a window that has since navigated elsewhere is refused.

Promises returned by send, once and the functions above are ZalgoPromises: they settle synchronously when they can, which keeps a chain inside a user gesture and avoids microtask lag in a background window. await works on them.

The rest of the API

| Export | Does | | --- | --- | | setup() | Start listening and say hello to the opener or parent. on and send run it; call it in a window that only needs to be reachable | | destroy() | Stop listening and drop every pending request | | cleanUpWindow(win) | Fail every request still waiting on a window that is going away | | markWindowKnown(win) | Treat a window as one that will acknowledge, before it has sent anything | | awaitWindowHello(win, timeout?, name?) | Resolves with { domain } once the window has said hello | | serializeMessage(win, domain, value) / deserializeMessage(win, origin, text) | Encode a value for a window the way a message would, to carry it another way (in a url, say) | | createProxyWindow(win?) / toProxyWindow(win) | Make, or look up, the ProxyWindow for a window | | ZalgoPromise, ProxyWindow, GLOBAL_KEY, MAJOR_VERSION, MESSAGE_NAME, WILDCARD | The pieces above, and the constants |

Two copies on one page

All of post-robot's state hangs off one window property keyed by major version, window.__post_robot_12__, and every message is tagged with that key. Two copies of the same major on one page share one listener, one set of handlers and one hello table, so a page with two libraries built on post-robot does not double-handle or drop messages. Two copies of different majors ignore each other's messages.

Changes in 12

Published as post-robot again (8 to 11 lived under @krakenjs). ES modules and TypeScript only. The serialization layer is sandestin. Gone, because no supported browser needs them: the Internet Explorer popup bridge (bridge.*, openBridge, linkWindow, linkUrl), the global-messaging fallback for IE11 and legacy Edge, the user-agent sniffing, the .ie.js builds and the __POST_ROBOT__ build flags, the mock:// domain test hooks, and the CommonJS entry point. Dependencies: zalgo-promise 3, cross-domain-utils 4 and sandestin; belter, cross-domain-safe-weakmap and universal-serialize are no longer used. Importing post-robot has no side effects: listeners start on the first on or send, or on setup(). The global key is now the major version rather than the exact version, so patch and minor releases on one page share a channel.

License

Apache-2.0