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

mpl

v0.3.0

Published

Build cloud apps without needing cloud infrastructure.

Readme

MPL

Build cloud apps without needing cloud infrastructure.

Magic Persistence Layer is a WebRTC peer-to-peer synchronization system for automerge documents.

Guide

This guide will demonstrate how to create a basic counter app using Electron, React, and MPL. First, start by creating a new Electron app using Electron Forge with the React template.

$ npm install -g electron-forge
$ electron-forge init demo --template=react
$ cd demo

Now, install MPL:

$ npm install --save mpl

In src/app.jsx, initialize the MPL store and add the counter to the view:

import React from 'react'
import MPL from 'mpl'

export default class App extends React.Component {
  constructor() {
    super()

    this.store = new MPL.Store((state, action) => {
      switch(action.type) {
        case "INCREMENT_COUNTER":
          return MPL.Automerge.change(state, "increment counter", (doc) => {
            doc.counter = (state.counter || 0) + 1
          })
        default:
          return state
      }
    })

    // Force App component to re-render when state changes
    this.store.subscribe(() => this.setState({}))
  }

  componentDidMount() {
    // Normally your app would get your document id via URL or from a file,
    // but here we will fix it to "1" so our clients join the same doc
    this.store.dispatch({ type: "OPEN_DOCUMENT", docId: "1" })
  }

  render() {
    return <div>
      <h2>Counter: { this.store.getState().counter }</h2>
      <button onClick={ () => this.store.dispatch({type: "INCREMENT_COUNTER"}) } >
        Increment
      </button>
    </div>
  }
}

Start two clients and try incrementing the counter by clicking the button, and you should see the counters synchronize on both clients:

$ npm start & npm start

API

Store

The Store class is modeled off of Redux and follows the same basic pattern.

new Store(reducer)

Constructor that accepts a reducer function. When an action is dispatched to the store, it first checks against MPL's provided reducer actions and then invokes your reducer if the action did not map to any of the provided ones.

getState()

Returns the current state object including all of your persisted data.

getHistory()

Returns the change history from the state.

Ex:

store.getHistory()
=> [
  {
    "change": {
      "actor": "61d8b814-463c-4092-b71d-7137873840e4",
      "seq": 1,
      "deps": {},
      "message": "new document",
      "ops": [...]
    },
    "snapshot": {
      "cards": [...],
      "lists": [...],
      "docId": "saffron-guangzhou-85"
    }
  }
]

dispatch(action)

Sends an action through your reducer. You should only modify the state through dispatch. Note: dispatch is a synchronous function.

subscribe(listener)

Allows to register a listener callback. All listeners are invoked whenver there is a state change in the store, including inbound changes that come in through other peers over the network.

save()

Returns a JSON serialization of your store's state. This is useful for persisting your state to a file, which can then be opened later by dispatching a "OPEN_DOCUMENT" action.

Provided Actions

MPL.Store provides several built-in actions to create, open, and merge documents. All document management should go through your MPL.Store instance so that aMPL can connect to the right peer group and broadcast state changes over the network.

"NEW_DOCUMENT"

Resets the store's state to a new document.

Ex:

this.store.dispatch({
  type: "NEW_DOCUMENT"
})

"OPEN_DOCUMENT"

Opens a new document. Accepts a docId or file blob as parameters (i.e. the serialized output from MPL.Store#save().

Ex:

this.store.dispatch({
  type: "OPEN_DOCUMENT", docId: "1234-5678-9"
})

"FORK_DOCUMENT"

Creates a fork of the current document, copying all of its current data but creating a new docId.

Ex:

this.store.dispatch({
  type: "FORK_DOCUMENT"
})

Development

Compiling

MPL is configured via Babel to use ES2016 syntax. The source code is located in src and compiled code in lib. Make sure to compile and commit before creating a new release:

$ npm run compile

Testing

To run tests:

$ npm run test

Versions

When it's time to cut a release do the following:

  1. Edit local package.json and set version number (eg. 0.0.5)
  2. Make sure all code is compiled:
$ npm run compile
  1. Create a commit, tag, and push:
$ git commit -a -m "v0.0.5"
$ git tag v0.0.5
$ git push --tags