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

@mallpopstar/partyline

v1.1.0

Published

Partyline is a JavaScript library that can send messages between APIs that support `postMessage`.

Downloads

9

Readme

Partyline ☎️

Partyline is a JavaScript library that can send messages between APIs that support postMessage. It is designed to allow you to create your own APIs that can communicate with each other, even if they are loaded from different origins.

Features

  • Send messages from APIs that support postMessage to any other API that supports postMessage, including:
    • window
    • iframe
    • web worker
    • MessageChannel
    • BroadcastChannel
  • Sending requests and responses
  • Subscribing to events
  • Easy to use API
  • Register your own request handlers
  • Ability to add your own custom transports
  • Written in TypeScript
  • Tree-shakes unused library code

Installation

npm install @mallpopstar/partyline

CDN

You can use partyline without installing it by using a CDN. You can use either unpkg or jsDelivr. If you use a CDN, you can access the library via the Partyline global variable.

Using unpkg

<script src="https://unpkg.com/@mallpopstar/partyline@latest/dist/partyline.min.js"></script>

Using jsDelivr

<script src="https://cdn.jsdelivr.net/npm/@mallpopstar/partyline@latest/dist/partyline.min.js"></script>

The library will be available on a global variable named partyline.

const { createReceiver, createSender } = partyline

Running the examples in this repo

Clone the repo and run the following commands:

npm install
npm run dev

Open the link indicated in your console. Open your console in the browser to see the logs.

Basic usage

import { createReceiver, createSender } from '@mallpopstar/partyline'

// receiving a message
const receiver = createReceiver()
receiver.connect(window)

receiver.onRequest('ping', (req, res) => {
  console.log('ping', req)
  res.send('Hello from receiver!')
})

receiver.onSubscribe('foo', (req, res) => {
  console.log('foo', req)
  res.send('response subscription')
})

// post request to receiver
const sender = createSender()
sender.connect(window)

sender.postRequest('ping', 'Hello from sender!').then(res => {
  console.log('pong', res)
})

sender.subscribe('foo', (val: string) => console.log('foo changed:', val))

Using iframe

From the parent window

import { createReceiver } from '@mallpopstar/partyline'

const receiver = createReceiver()
receiver.connect(iframe.contentWindow)

receiver.onRequest('ping', (req, res) => {
  console.log('ping', req)
  res.send('pong')
})

From the child window (iframe)

import { createSender } from '@mallpopstar/partyline'

const sender = createSender()
sender.connect(window.parent)

sender.postRequest('ping', { message: 'Hello from sender!' }).then(res => {
  console.log('pong', res)
})

Using web worker

From the main thread

Click here to see a live example.

import { createReceiver, loadWorker } from '@mallpopstar/partyline'

const receiver = createReceiver()
const messageChannel = new MessageChannel()

receiver.onRequest('ping', (req, res) => {
  console.log('ping', req)
  res.send('pong')
})

// loadWorker is a special function that will load the worker cross-origin
const worker = loadWorker('worker.js')
receiver.connect(worker)

From the worker

import { createSender } from '@mallpopstar/partyline'

const sender = createSender()

sender.connect(self)
sender.postRequest('ping', { message: 'Hello from sender!' }).then(res => {
  console.log('pong', res)
})

Using BroadcastChannel

From first website

import { createReceiver } from '@mallpopstar/partyline'

const receiver = createReceiver()
const channel = new BroadcastChannel('my-channel')

receiver.onRequest('ping', (req, res) => {
  console.log('ping', req)
  res.send('pong')
})

receiver.connect(channel)

From second website

import { createSender } from '@mallpopstar/partyline'

const sender = createSender()
const channel = new BroadcastChannel('my-channel')

sender.connect(channel)
sender.postRequest('ping', { message: 'Hello from sender!' }).then(res => {
  console.log('pong', res)
})

Using MessageChannel

From receiving port

import { createReceiver } from '@mallpopstar/partyline'

const receiver = createReceiver()
const channel = new MessageChannel()

receiver.onRequest('ping', (req, res) => {
  console.log('ping', req)
  res.send('pong')
})

receiver.connect(channel.port1)

From sending port

import { createSender } from '@mallpopstar/partyline'

const sender = createSender()
const channel = new MessageChannel()

sender.connect(channel.port2)
sender.postRequest('ping', { message: 'Hello from sender!' }).then(res => {
  console.log('pong', res)
})

Sender options

By default the sender will timeout a request after 10 seconds. You can change this by passing in a timeout option:

import { createSender } from '@mallpopstar/partyline'

const sender = createSender()
// if you pass in 0, it will never timeout
sender.setOptions({ timeout: 1000 })

Subscribing to events

If you want to subscribe to events, you can use the subscribe request method. This will send a request to the receiver and then the receiver use this to send back responses subscribers.

import { createReceiver, createSender } from '@mallpopstar/partyline'

const receiver = createReceiver()
const sender = createSender()
const subscribers = new Map<string, any>()

let count = 0
receiver.onSubscribe('count', (req, res) => {
  console.log('foo', req)
  subscribers.set(req.id, res)
  setInterval(() => {
    count++
    subscribers.forEach(res => res.send(count))
  }, 1000)
})

receiver.onUnsubscribe('count', req => {
  console.log('unsubscribed', req)
  subscribers.delete(req.id)
})

const unsubscribe = sender.subscribe('count', req => {
  console.log('count', req)
  if (req.body >= 3) {
    unsubscribe()
  }
})

Using IChannel to create your own transports

If you want to create your own transport, you can use the IChannel interface provided in Partyline. This interface is used by the createReceiver and createSender methods to create the default transports. You can use this to create adapters for WebSockets, WebRTC, or other transports.

Super simple example

import { IChannel } from '@mallpopstar/partyline'

class MyChannel implements IChannel {
  #subscriptions: any[] = []

  onmessage?: (e: any) => void
  
  postMessage(message: any): void {
    this.#subscriptions.forEach(subscription => subscription(message))
  }
  addEventListener(_: 'message', listener: (e: any) => void): void {
    this.#subscriptions.push(listener)
  }
  removeEventListener(_: 'message', listener: (e: any) => void): void {
    this.#subscriptions = this.#subscriptions.filter(subscription => subscription !== listener)
  }
}

Related projects

There are a few other libraries that do similar things to Partyline:

  • https://github.com/krakenjs/zoid
  • https://github.com/dollarshaveclub/postmate
  • https://github.com/AshleyScirra/via.js

If you are looking for a library that can load 3rd-party js files and fill in the gaps, check out Partytown 🎉.

License

Partyline is licensed under the MIT license.