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

patchpack

v0.4.2

Published

Json patch serializer

Downloads

37

Readme

PatchPack

A binary JsonPatch serializer based on schema. Efficiently encode state object and JsonPatch in to compact byte buffers and then decode them back in to objects on the receiver. Integrates very well with observable state and WebSockets.

Originally it was part of mosx framework, but then it moved to separate package.

Motivation

I was working on an magx game server framework that used WebSockets to syncronize state between server and clients. Syncronization principle is simple: first server sends full state to clients then on every change sends patches in JsonPatch format. I have found the problem that sending a lot of patches without serialization is a waste of bandwidth.

As state's schema is known on server side it can be sent to the clients, then state and each patch can be encoded based on that schema on server side and decoded back on client side. State schema is not static that means it must be also syncronized with clients. This sophisticated approach can significantly reduce patch size and bandwidth usage.

Concept

Installation

npm install --save patchpack

Browser

A browser version of patchpack is also available:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/browser/patchpack.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/browser/patchpack.js"></script>

Example

/** Server side */

import { PatchPack } from "patchpack"

class Client {
  constructor(public name: string, public info = "") {}
}

// initial state
const state: any = {
  clients: {
    "1": new Client("Foo"),
    "2": new Client("Baz", "FooBaz"),
  },
  objects: [
    { id: 1, name: "Foo" },
    { id: 2, name: "Foo", foo: "Baz" },
  ],
  foo: {
    baz: false
  }
}

// create patchpack instance and define schema types
const ppServer = new PatchPack({
  State: ["clients", "objects", "foo"],
  Client, // it is recommended to use class in schema
  Object: ["id", "name", "foo"],
  Foo: ["baz"]
})

const encodedStateWithTypes = ppServer.encodeState(state)
console.log(encodedStateWithTypes.length)
// 135

const encodedState = ppServer.encodeState(state, false)
console.log(encodedState.length)
// 60

console.log(JSON.stringify(state).length)
// 165

const client = new Client("FooBaz", "test" )
state.clients["3"] = client

const patch1 = { op: "add", path: "/clients/3", value: client }
const encodedPatch1 = ppServer.encodePatch(patch1)
console.log(encodedPatch1.length)
// 22

console.log(JSON.stringify(patch1).length)
// 72

// generate patch
const patch2 = { op: "replace", path: "/foo/baz", value: true }
const encodedPatch2 = ppServer.encodePatch(patch2)

console.log(encodedPatch2.length)
// 5

console.log(JSON.stringify(patch2).length)
// 47

Send encodedStateWithTypes, encodedPatch1 and encodedPatch2 to Client and decode them:

/** Client side */
const ppClient = new PatchPack()

const decodedState = ppClient.decodeState(encodedStateWithTypes)
console.log(decodedState)

// {
//   clients: {
//     '1': { name: 'Foo', info: '' },
//     '2': { name: 'Baz', info: 'FooBaz' }
//   },
//   objects: [
//      { id: 1, name: 'Foo' },
//      { id: 2, name: 'Foo', foo: 'Baz' } ],
//   foo: { baz: false }
// }

const decodedPatch1 = ppClient.decodePatch(encodedPatch1)
console.log(decodedPatch1)

// {
//   op: 'add',
//   path: '/clients/3',
//   value: { name: 'FooBaz', info: 'test' }
// }

const decodedPatch2 = ppClient.decodePatch(encodedPatch2)
console.log(decodedPatch2)

// { op: 'replace', path: '/foo/baz', value: true }

License

MIT