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

@opensea/vessel

v0.6.18

Published

Promise based wrapper for postMessage API 🚢

Downloads

19,235

Readme

OpenSea Vessel 🚢

A promise based wrapper for the postMessage API for communications between a parent app and an iframed child app.

OpenSea Vessel can be used to send messages between a parent app and an iframed app, and await responses to messages. Example: Confirmation of receipt, result of RPC call.

Installation

You guessed it!

pnpm install @opensea/vessel

Getting Started

Import the Vessel class

import { Vessel } from "@opensea/vessel"

Vessel class contains logic for sending and receiving messages via the postMessage. It can be used in both the parent app and child app.

Parent app

The parent app mounts the iframe that loads the child app. The parent app must pass a reference to the child iframe element into the Vessel class constructor. It is used to access the postMessage method of the iframe window.

// NOTE: Replace with reference to your iframe
const iframe = document.createElement("iframe")
const vessel = new Vessel({ iframe })

Child app

The child app is mounted in an iframe and has access to the postMessage API of its parent app's window by default. It does not require any extra params to be initialized.

const vessel = new Vessel()

Vessel Constructor

Vessel instances can be constructed with an options object. It includes the following properties:

| Property | Description | Default | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | | iframe | The iframe element to communicate with. If not provided the constructed instance will be a child vessel. | undefined (instance is child vessel) | | application | The application name to use for vessel messages. Must be shared between parent and child. | "opensea-vessel" | | defaultTimeout | Default number of milliseconds to wait for a message response before throwing a TimeoutError | 5_000 (5s) | | handshakeTimeout | Number of milliseconds to wait for a handshake response before throwing a HandshakeTimeoutError | 10_000 (10s) | | targetOrigin | The target origin for the iframe or parent window to connect to. Directly used as postMessage targetOrigin. | "*" (Any origin) | | debug | Whether to log debug messages to the console. | false |

Sending messages

Sending messages from parent and child via a Vessel class instance is the same.

// Examples
const response = await vessel.send("Any payload!")
const objectPayload = await vessel.send({
  foo: "bar",
  baz: { odee: ["nested", "is", "fine"] },
})
const customTimeout = await vessel.send(
  "If no response in 3 seconds this promise will reject.",
  { timeout: 3_000 },
)
const noTimeout = await vessel.send("This promise might never resolve.", {
  timeout: undefined,
})

The send method takes any JSON serializable payload as first param and an options object as the second. The options object includes the following properties:

| Property | Description | Default | | --------- | ------------------------------------------------------------------------------ | ------------ | | timeout | Number of milliseconds to wait for a response before throwing a TimeoutError | 5_000 (5s) |

Handling incoming messages

The Vessel class can be used to add message listeners and exposes a convenient reply function for listeners to use. Message listener must return a boolean to indicate whether they handled the message or not.

type VesselMessageListener = (
  message: VesselMessage,
  reply: (response: unknown, options: ReplyOptions) => void,
) => boolean

// Example listener
vessel.addMessageListener((message, reply) => {
  if (message.shouldBeHandledHere) {
    const result = handleThisMessage(message)
    reply(result)
    return true
  } else {
    return false
  }
})

Replying with errors

Sometimes the response to a message is an error and it is preferrable for the send method to throw an error for the sender to handle. Replying to a message with the options error boolean set to true will cause sender to reject the send promise with the payload as an error when teh response is received.

interface ReplyOptions {
  error?: boolean
}

// Example reply error
vessel.addMessageListener((message, reply) => {
  if (message.shouldBeHandledHere) {
    try {
      const result = handleThisMessage(message)
      reply(result)
    } catch (error) {
      reply(
        { reason: "Handling failed", stepsToFix: [1, 2, 3] },
        { error: true },
      )
    }
    return true
  } else {
    return false
  }
})