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

@toju.network/sol

v0.1.4

Published

Decentralized storage SDK for Solana via Storacha - pay with SOL, store on IPFS

Downloads

600

Readme

Storacha SOL

Crypto-native payments for storage on Storacha with SOL. No credit card needed.

Here are a couple of things you can do with this package:

  • Estimate upload fees based on the file size and duration
  • Make SOL payments for Storage on Storacha
  • Multiple file (directory) uploads
  • Show how much time is left to expiry
  • View your upload history (all files you've stored with their details)
  • Get expiration warnings via email before your files expire
  • Automatic deletion of expired files from Storacha
  • Renew/extend storage duration for existing uploads

Stuffs we hope to cover or extend:

  • Allow payments from other chains. (Filecoin next)
  • Include implementations for other libs. Right now, we only have React. Hoping to cover, Vue, Svelte etc.

Usage

First, install the package with your preferred package manager

pnpm add storacha-sol

The package exposes a react hook useDeposit which you can access the client with. Because this runs on Solana for now, you'll need to install any of your preferred solana wallet-adapter libs tailored for React or JS in general

We recommend this one: @solana/wallet-adpater-react. It'll come in handy when you'll need it to sign the transaction from client.createDeposit(args)

In your component, import the useDeposit hook like so:

import { useDeposit } from 'storacha-sol';

const UploadComponent = () => {
  const client = useDeposit('testnet');
  return <>// some markup</>;
};

From the snippet above, you'll see that the hook takes an environment argument "testnet". If you leave it as is, Typescript would start crying. So, to appease it, you should import the Environment type from storacha-sol and infer it.

import { useDeposit, Environment } from "storacha-sol"
...

const client = useDeposit("testnet" as Environment)

In your component, we'll assume you already have file and duration state variables

import { useDeposit, Environment } from 'storacha-sol';
import { useSolanaWallet } from '@solana/wallet-adapter-react';

const UploadComponent = () => {
  const [selectedFiles, setSelectedFiles] = useState<File>();
  const [storageDuration, setStorageDuration] = useState(30);
  const client = useDeposit('testnet' as Environment);
  const { publicKey, signTransaction } = useSolanaWallet();

  return <>// some markup</>;
};

createDeposit expects the following args: payer (which is the publicKey, imported from wallet-adapter), file, duration, and the callback to sign a transaction.

See a sample of how you can achieve this below:

const result = await client.createDeposit({
  file,
  durationDays: storageDuration,
  payer: publicKey,
  signTransaction: async (tx) => {
    toast.loading('Please sign the transaction in your wallet...', {
      id: 'upload-progress',
    });

    try {
      const signed = await signTransaction(tx);
      toast.loading('Transaction sent to network...', {
        id: 'upload-progress',
      });

      return signed;
    } catch (signError) {
      console.error('❌ Transaction signing failed:', signError);
      throw new Error(
        `Transaction signing failed: ${signError instanceof Error ? signError.message : 'Unknown error'}`
      );
    }
  },
});

storacha-sol is type-safe, so you can always explore the content of the declaration file to see the structure. You could take a look at UploadResult, for starters.

and when result is successful, you can proceed with any other action you choose to carry out in your app.

if (result.success) {
  // do more stuff
}

An edge-case you may want to consider before calling createDeposit is to check if the estimated storage cost is more than the wallet balance of the user, as this would fail to create the transaction.

You can use client.estimateStorageCost to get the values in SOL and compare if the balance is less than what was estimated before paying and provide a reasonable error message for your end-users.

View Upload History

You can fetch all uploads associated with a wallet address:

const client = useDeposit('testnet' as Environment);
const history = await client.getUserUploadHistory(publicKey.toString());

console.log(history.userHistory); // Array of all deposits

Each deposit in the history includes:

  • File details (name, size, type, CID)
  • Expiration date
  • Deletion status (active, warned, deleted)
  • Transaction hash
  • Duration and cost information

Email Expiration Warnings

When creating a deposit, you can optionally provide an email address to receive expiration warnings:

const result = await client.createDeposit({
  file,
  durationDays: storageDuration,
  payer: publicKey,
  userEmail: '[email protected]', // Optional email for expiration warnings
  signTransaction: async (tx) => {
    const signed = await signTransaction(tx);
    return signed;
  },
});

If provided, you'll receive an email notification 7 days before your file expires, giving you time to extend the storage duration (feature coming soon!).

The warning email includes:

  • File name and CID
  • Exact expiration date
  • Number of days remaining
  • Direct link to view your file on IPFS

Automatic Cleanup

Files that have expired are automatically deleted from Storacha storage. This happens through a scheduled job that:

  1. Identifies expired deposits
  2. Removes the data from Storacha (including shards)
  3. Updates the deletion status in the database

Your upload history will show the deletion status, so you can track which files are still active, warned, or deleted.

Storage Renewal

Extend the storage duration for your existing uploads before they expire:

const client = useDeposit('testnet' as Environment);
const { publicKey, signTransaction } = useSolanaWallet();

// First, get a quote to see what it'll cost
const quote = await client.getStorageRenewalCost(cid, 30); // 30 additional days

console.log(`Current expiration: ${quote.currentExpirationDate}`);
console.log(`New expiration: ${quote.newExpirationDate}`);
console.log(`Cost: ${quote.costInSOL} SOL`);

const result = await client.renewStorageDuration({
  cid,
  additionalDays: 30,
  payer: publicKey,
  signTransaction: async (tx) => {
    const signed = await signTransaction(tx);
    return signed;
  },
});

if (result.success) {
  console.log('Storage renewed! Transaction:', result.signature);
}

How it works:

  • getStorageRenewalCost() shows you the cost and new expiration date before committing
  • renewStorageDuration() creates a payment transaction (same flow as initial upload)
  • After payment confirms, your file's expiration date gets updated

Usage with Vite

When using this SDK in a project built with Vite, you may encounter a ReferenceError: process is not defined. This is because Vite does not automatically polyfill the Node.js process global, which this library may use.

To resolve this, you can define process.env to safely access NODE_ENV and additionally install vite-plugin-node-polyfills as a dev dependency and edit your vite.config.ts file:

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nodePolyfills } from 'vite-plugin-node-polyfills';

export default defineConfig({
  plugins: [react(), nodePolyfills()],
  // ... other config
  define: {
    'process.env': {
      NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'production'),
    },
  },
});

This will prevent the runtime error and allow the SDK to function correctly.

Want to contribute?

Read the Contributing guide