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

jsonld-dweb-loader

v1.2.0

Published

JSON-LD document loader for IPFS and IPLD URIs

Downloads

3

Readme

jsonld-dweb-loader

JSON-LD document loader for IPFS and IPLD

{
	"@context": "dweb:/ipfs/QmUFeUYXqyKa1mXLyfiCkm1MDbwYPTFBpyKvW7Nhy98Ks1",
	"@type": "Digest",
	"digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1",
	"digestValue": "981ec496092bf6ee18d6255d96069b528633268b"
}

<<< Golang implementation >>>

Motivation

Suppose you have some JSON-LD, like this example taken from the W3C Security Vocabulary:

{
	"@context": "https://w3id.org/security/v1",
	"@type": "Digest",
	"digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1",
	"digestValue": "981ec496092bf6ee18d6255d96069b528633268b"
}

Making any sense of this document requires fetching the context from https://w3id.org/security/v1 to resolve the properties and types. For example, the context is what tells us that digestValue is an abbrviation of https://web-payments.org/vocabs/security#digestValue.

Contexts are wonderful and elegant and an huge feature of JSON-LD, but just to be practical in the real world, contexts need to be cached so that we don't have to hit the network every time we see someone using something from the W3C security vocabulary (and the JSON-LD folks will be the first to tell you this).

This is all well and good, but what if I'm not the W3C and want to publish a context that I expect to re-use (or other people to re-use)? I don't want to commit to hosting something on a permanent URL until the end of time. And I probably don't have as good security practices as they do, so if someone gets into my server they can rename digestValue to http://white.house/NuclearLaunchCodes or something nefarious without anyone noticing (you never really know if the context that you get served was the same context that the author of the document intended). I want to cache my contexts, but I'm not in a position to host it at a URL.

enter the decentralized web

Puttting Contexts on IPFS

IPFS is a decentralized filesystem that names files by their hash and lets you ask for them from the network at large, from no particular location, just whoever happens to have them, similar to BitTorrent. You can pin files you really care about to guarantee their availability, but any node that has the file will help you retrieve it.

Even better, IPFS can caches files automatically: once you fetch a file from the network, you become your own closest peer, and subsequent requests for that file return without touching the network at all. The beauty of content-addressing is that we know the contents haven't changed!

So what if I was worried the W3C was going to get hacked, or if I just wanted a built-in way of caching my contexts, I could use IPFS like this:

First, I get the file from its current URL and add it to IPFS

joel$ curl -L https://w3id.org/security/v1 | ipfs add
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   310  100   310    0     0   2259      0 --:--:-- --:--:-- --:--:--  2246
100  2019  100  2019    0     0   5790      0 --:--:-- --:--:-- --:--:--  5790
added QmUFeUYXqyKa1mXLyfiCkm1MDbwYPTFBpyKvW7Nhy98Ks1 QmUFeUYXqyKa1mXLyfiCkm1MDbwYPTFBpyKvW7Nhy98Ks1
joel$
joel$ ipfs cat QmUFeUYXqyKa1mXLyfiCkm1MDbwYPTFBpyKvW7Nhy98Ks1
{
  "@context": {
    "id": "@id",
    "type": "@type",

    "dc": "http://purl.org/dc/terms/",
    "sec": "https://w3id.org/security#",
    "xsd": "http://www.w3.org/2001/XMLSchema#",

    "EcdsaKoblitzSignature2016": "sec:EcdsaKoblitzSignature2016",
...

Then I rename my JSON-LD document to reference the IPFS URI:

{
	"@context": "dweb:/ipfs/QmUFeUYXqyKa1mXLyfiCkm1MDbwYPTFBpyKvW7Nhy98Ks1",
	"@type": "Digest",
	"digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1",
	"digestValue": "981ec496092bf6ee18d6255d96069b528633268b"
}

Let's even add that document to IPFS, just for fun:

joel$ ipfs add sample.jsonld
added QmXjY3nz81qG99vbMF4Tb2NeSFmUdWBUG7ecYVtvnGxrXt sample.jsonld
joel$ ipfs cat QmXjY3nz81qG99vbMF4Tb2NeSFmUdWBUG7ecYVtvnGxrXt
{
  "@context": "dweb:/ipfs/QmUFeUYXqyKa1mXLyfiCkm1MDbwYPTFBpyKvW7Nhy98Ks1",
  "@type": "Digest",
  "digestAlgorithm": "http://www.w3.org/2000/09/xmldsig#sha1",
  "digestValue": "981ec496092bf6ee18d6255d96069b528633268b"
}

Then unleash the magic!

const createDocumentLoader = require("jsonld-dweb-loader")
const IPFS = require("ipfs")
const jsonld = require("jsonld")

const ipfs = new IPFS({})
ipfs.on("ready", () => {
	const doc = "dweb:/ipfs/QmXjY3nz81qG99vbMF4Tb2NeSFmUdWBUG7ecYVtvnGxrXt"
	const documentLoader = createDocumentLoader(ipfs)
	jsonld.expand(doc, { documentLoader }, (err, expanded) => {
		console.log(err, JSON.stringify(expanded))
		process.exit()
	})
})
joel$ node test.js
context: dweb:/ipld/zdpuB2s6SPPu2TPv6RBUY7FhJkghnYfc7dDvz5Luyw4wosde1
document: ipfs://QmPm5sCx6HLSmdJHFrozmsVNxC6mrE3VMHH7XuTQmtqUuA
{
  "@context": "dweb:/ipld/zdpuB2s6SPPu2TPv6RBUY7FhJkghnYfc7dDvz5Luyw4wosde1",
  "@graph": [
    {
      "@type": "schema:Person",
      "schema:knows": {
        "@type": "schema:Person",
        "schema:name": "Bob"
      },
      "schema:name": "Alice"
    }
  ],
  "prov:wasAttributedTo": {
    "@type": "schema:Person",
    "schema:name": "Eve"
  }
}

Support

This loader supports JSON-encoded contexts and documents on IPFS under the dweb:/ipfs/ and ipfs:// URI schemes (the loader will atempt to parse those files as JSON and will throw an error if that fails), as well as the dag-cbor and dag-json IPLD formats, which deserialize directly to JSON.