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

pinning-aggregation

v1.0.0

Published

Use multiple pinning services like they are one

Downloads

4

Readme

IPFS Pinning Aggregation

This package provides a way to aggregate multiple pinning services, like they are one. It includes vanilla IPFS node pinning, as well as pinning to Filecoin via Powergate.

Context and problem statement

We wanted to add additional backend for pinning to Ceramic network node, namely on Filecoin through Powergate.

We want to:

  • use IPFS pinnning or Filecoin pinning separately or simultaneously,
  • select particular pinning backend via runtime configuration.

Semantics

Functions

Every pinning backend is expected to provide these functions:

  1. pin record by its CID,
  2. remove pin by its CID.

Multiple pinning backends

Having multiple pinning backends simultaneously leads to distributed transactions, if done thoroughly. We have following expectations:

  • 90% of the time, only one pinning backend is used,
  • pinning is an idempotent operation,
  • if multiple pinning backends are used simultaneously, the node must pin on all the backends, yet it treats unpin operation on best effort basis.

Thus, instead of distributed transactions, we can use light-weight Promises.

Components

Based on the semantics, it makes sense to have:

  1. pure pinning backends - responsible for pinning records,
  2. pinning backends aggregator - responsible for pinning records using multiple pinning backends simultaneously,

To add a new pinning backend, one should add one more class implementing IPinning interface, that conforms to IPinningStatic, and add it to a list of available backends.

Configuration

API

We want to achieve common way of configuring different pinning backends, that should work for CLI as command-line parameter, as well as for environment variable. For backends it should contain host-port of the used service endpoint, as well as additional authentication information. Considered YAML/JSON configuration file and URL Connection string. The latter seems to fit the bill without introducing a heavy indirection layer.

Connection string is formed as valid URL, for example:

ipfs://localhost:5001
ipfs+https://example.com:3342
powergate+http://example.com:4001

Every pinning backend is assigned a unique string that we call designator below. PinningAggregation gets a protocol component of connection strings passed, gets the first part of it before an optional plus (+) symbol, and treats it as a designator for a backend. For the examples above, designator searched is ipfs. Rest of the connection string is parsed by particular backend.

IPFS. Connection string looks like ipfs://<host>:<port> or ipfs+http://<host>:<port> or ipfs+https://<host>:<port>. It is translated into http://<host>:<port>, http://<host>:<port>, https://<host>:<port> correspondingly. Here there is a special hostname __context used, which commands the pinning backend to use IPFS connection provided in IContext.

Powergate. Powergate requires token for authentication purposes. We pass it as a query param. Connection string looks like powergate://<host>:<port>?token=<token>, powergate+http://<host>:<port>?token=<token> or powergate+https://<host>:<port>?token=<token>. It is translated into http://<host>:<port>, http://<host>:<port>, https://<host>:<port> correspondingly, and set the token passed.

Usage

First, add the package as a dependency:

npm add pinning-aggregation

Then instantiate PinningAggregation. We anticipate some applications already having IPFS connection, so we provide it in a context parameter.

import {
  PinningAggregation,
  IpfsPinning,
  PowergatePinning,
} from "pinning-aggregation";
const context = {
  ipfs: EXISTING_IPFS_CONNECTION, // May be null or undefined
};
const pinning = await PinningAggregation.build(context, [
  "ipfs://__context",
  "ipfs+https://example.com:3342",
  "powergate+http://example.com:4001?token=something-special",
  [IpfsPinning, PowergatePinning],
]);
await pinning.open(); // Must call open before doing anything
await pinning.pin(new CID("QmSnuWmxptJZdLJpKRarxBMS2Ju2oANVrgbr2xWbie9b2D"));
await pinning.close(); // Must call on application shutdown

This would use 3 pinning instances:

  • vanilla IPFS provided in context variable,
  • vanilla IPFS located at https://example.com:3342,
  • Powergate located at http://example.com:4001, with authentication token something-special.

The module uses dynamic imports (await import) to reduce size of a resulting application bundle. So, if you are going to use remote ipfs, make sure to add ipfs-http-client as a dependency to your application. If you are going to use Powergate pinning, add @textile/powergate-client as well.

Ancillary methods

In addition to pin and unpin functionality, the package provides list of pins per backend (#ls) and backend info (#info). An aggregation that contains single Powergate backend would output like below:

{
    "powergate@wRVpk643xlIc86w608VW7JvXeezzoDG1dLqEtGNHoYo=": {
        "id": "321ff612-85a8-46c4-93b6-86e97964ce45",
        "defaultStorageConfig": {
            "hot": {
                "enabled": true,
                "allowUnfreeze": false
            },
            "cold": {
                "enabled": true,
                "filecoin": {
                    "repFactor": 1,
                    "dealMinDuration": 518400,
                    "excludedMinersList": [],
                    "trustedMinersList": [],
                    "countryCodesList": [],
                    "renew": {
                        "enabled": false,
                        "threshold": 0
                    },
                    "addr": "t3rndyswpparggro2ome2b2j4rrpkg3yh4gpfpe426vneangwooprjor44dbwti2omsd7vkcb2lt6fcwpdt6sq",
                    "maxPrice": 0
                }
            },
            "repairable": false
        },
        "balancesList": [
            {
                "addr": {
                    "name": "Initial Address",
                    "addr": "t3rndyswpparggro2ome2b2j4rrpkg3yh4gpfpe426vneangwooprjor44dbwti2omsd7vkcb2lt6fcwpdt6sq",
                    "type": "bls"
                },
                "balance": 3999802806680231
            }
        ]
    }
}

Here powergate@wRVpk643xlIc86w608VW7JvXeezzoDG1dLqEtGNHoYo= is a unique backend id, that is constructed as designator@base64url(sha256(connectionString)).