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

@siafoundation/sia

v0.3.0

Published

TypeScript SDK for building decentralized storage apps on the [Sia](https://sia.tech) network.

Readme

@siafoundation/sia

TypeScript SDK for building decentralized storage apps on the Sia network.

Install

npm install @siafoundation/sia

Bundler setup

This package includes a WebAssembly binary, so your bundler needs to be configured to handle .wasm files.

Vite

npm install vite-plugin-wasm vite-plugin-top-level-await
// vite.config.ts
import wasm from 'vite-plugin-wasm'
import topLevelAwait from 'vite-plugin-top-level-await'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [wasm(), topLevelAwait()],
  optimizeDeps: {
    exclude: ['@siafoundation/sia'],
  },
  resolve: {
    alias: {
      'sia-wasm': '@siafoundation/sia/wasm',
    },
  },
})

Next.js

// next.config.ts
const nextConfig = {
  webpack: (config) => {
    config.resolve.alias['sia-wasm'] = require.resolve('@siafoundation/sia/wasm')
    config.experiments = { ...config.experiments, asyncWebAssembly: true }
    return config
  },
}
export default nextConfig

TypeScript

Add to your tsconfig.json so the sia-wasm alias resolves types:

{
  "compilerOptions": {
    "paths": {
      "sia-wasm": ["./node_modules/@siafoundation/sia/wasm/sia.d.ts"]
    }
  }
}

Usage

Initialize

Call initSia() once before using any other SDK functions:

import { initSia } from '@siafoundation/sia'

await initSia()

Authentication

Authentication is a two-phase flow: first connect your app to an indexer, then register with a recovery phrase. On subsequent visits, reconnect using the stored app key.

New user

import {
  Builder,
  SiaClient,
  generateRecoveryPhrase,
  toHex,
} from '@siafoundation/sia'

const indexerUrl = 'https://app.sia.storage'

// 1. Request a connection from the indexer
const builder = new Builder(indexerUrl)

await builder.requestConnection(JSON.stringify({
  appID: appKeyHex,       // 32-byte hex app identifier
  name: 'My App',
  description: 'A decentralized storage app',
  serviceURL: 'https://myapp.com',
}))

// 2. Direct the user to approve the connection
const approvalUrl = builder.responseUrl()
// Show this URL to the user — they visit it to authorize your app

// 3. Wait for the user to approve
await builder.waitForApproval()

// 4. Register with a recovery phrase to get an authenticated SDK
const phrase = generateRecoveryPhrase()
// Display the phrase for the user to save
const sdk = await builder.register(phrase)

// 5. Wrap in a SiaClient for upload/download
const client = new SiaClient(sdk, indexerUrl)

// 6. Export and persist the app key for reconnection
const appKey = sdk.appKey()
const keyHex = toHex(appKey.export())
// Store keyHex in localStorage or similar

CORS fallback: If requestConnection fails due to CORS, you can have the user run the POST manually (e.g. via curl) and pass the response to builder.setConnectionResponse(appKeyHex, responseJson).

Returning user

On subsequent visits, reconnect using the stored app key — no approval or recovery phrase needed:

import { connect, AppKey, fromHex } from '@siafoundation/sia'

const appKey = new AppKey(fromHex(storedKeyHex))
const client = await connect('https://app.sia.storage', appKey)
// Returns a SiaClient if recognized, or null if the key is unknown

Upload

The upload function splits a file into slabs and uploads them in parallel using Web Workers.

import { upload } from '@siafoundation/sia'

const object = await upload(client, file, (progress) => {
  console.log(`${progress.phase}: ${progress.slabsComplete}/${progress.slabsTotal} slabs`)
})

// Pin the object to the indexer so it persists
await client.sdk.pinObject(object)

For smaller files, you can also upload directly on the main thread without workers:

import { UploadOptions } from '@siafoundation/sia'

const data = new Uint8Array(await file.arrayBuffer())
const opts = new UploadOptions()
const object = await client.sdk.upload(data, opts, (current, total) => {
  console.log(`${current}/${total} shards`)
})
await client.sdk.pinObject(object)

Download

import { download } from '@siafoundation/sia'

const data = await download(client, object, (progress) => {
  console.log(`${progress.phase}: ${progress.bytesComplete}/${progress.bytesTotal} bytes`)
})

// data is a Uint8Array of the decrypted file contents

For partial reads (e.g. video seeking), use a range download — only the overlapping slabs are fetched:

const chunk = await download(client, object, onProgress, {
  range: { offset: 0, length: 1024 * 1024 }, // first 1 MB
})

Metadata

Attach and read metadata on objects:

// Write metadata
const meta = new TextEncoder().encode(JSON.stringify({
  name: 'photo.jpg',
  type: 'image/jpeg',
  size: file.size,
}))
object.updateMetadata(meta)
await sdk.updateObjectMetadata(object)

// Read metadata
import { decodeMetadata } from '@siafoundation/sia'
const parsed = decodeMetadata(object.metadata())

Sharing

// Create a share link valid for 24 hours
const shareUrl = client.sdk.shareObject(object, Date.now() + 86_400_000)

// Download a shared object
const shared = await client.sdk.sharedObject(shareUrl)
const data = await download(client, shared)

API

Top-level exports

| Export | Description | |--------|-------------| | initSia() | Initialize the WASM module (call once at startup) | | SiaClient | Wrapper that bundles an SDK instance with connection details | | connect(indexerUrl, appKey) | Reconnect a returning user — returns SiaClient \| null | | upload(client, file, onProgress, numWorkers?) | Parallel multi-worker file upload | | download(client, object, onProgress?, config?) | Parallel multi-worker download (full or range) | | generateRecoveryPhrase() | Generate a 12-word BIP-39 recovery phrase | | validateRecoveryPhrase(phrase) | Validate a recovery phrase | | fetchHostSettings(address) | Connect to a host via WebTransport and fetch its settings | | setLogLevel(level) | Control WASM log verbosity ("debug", "info", "warn", "error") | | toHex(bytes) / fromHex(hex) | Convert between Uint8Array and hex strings | | decodeMetadata(bytes) | Decode object metadata from bytes to JSON |

SDK

Instance methods available on the sdk property of SiaClient.

| Method | Description | |--------|-------------| | upload(data, options, onProgress) | Upload a Uint8Array on the main thread | | download(object, options, onProgress) | Download an object on the main thread | | downloadRange(object, offset, length, options, onSector) | Download a byte range — only fetches overlapping slabs | | streamingUpload(totalSize, options, onProgress) | Start a streaming upload that reads chunks on demand | | pinObject(object) | Pin an object to the indexer so it persists | | deleteObject(key) | Delete an object by its hex key | | object(key) | Retrieve a pinned object by its hex key | | updateObjectMetadata(object) | Update an object's metadata on the indexer | | shareObject(object, validUntilMs) | Create a share URL valid until the given timestamp | | sharedObject(shareUrl) | Retrieve a shared object from a share URL | | objectEvents(cursor?, limit) | List object events for syncing (cursor-based pagination) | | account() | Returns account information | | hosts() | Returns available hosts as a JSON array | | pruneSlabs() | Prune unused slabs from the indexer | | appKey() | Returns the AppKey used by this SDK instance |

Builder

Connection builder — authenticate with an indexer.

| Method | Description | |--------|-------------| | new Builder(indexerUrl) | Create a builder for the given indexer URL | | requestConnection(appMetaJson) | Request a new app connection with metadata | | responseUrl() | Returns the URL the user must visit to authorize | | waitForApproval() | Polls until the user approves the connection | | register(phrase) | Register with a recovery phrase — returns an SDK | | connected(appKey) | Reconnect with an existing AppKey — returns SDK \| null | | setConnectionResponse(appIdHex, json) | Set a pre-fetched connection response (CORS fallback) |

AppKey

Ed25519 app key for signing and authentication.

| Method | Description | |--------|-------------| | new AppKey(key) | Import from a 64-byte keypair or 32-byte seed | | publicKey() | Returns the hex-encoded public key | | sign(message) | Sign a message, returns 64-byte signature | | verifySignature(message, signature) | Verify a signature against a message | | export() | Export the full 64-byte ed25519 keypair |

PinnedObject

An encrypted object stored on Sia.

| Method | Description | |--------|-------------| | id() | Returns the object's hex ID | | size() | Total size in bytes | | slabCount() | Number of slabs in the object | | slabs() | Slab layout with offsets, lengths, and host keys | | slabLengths() | Data length of each slab as an array | | metadata() | Returns metadata as a Uint8Array | | updateMetadata(bytes) | Update the object's metadata | | seal(appKey) | Serialize for offline storage (returns JSON) | | PinnedObject.open(appKey, json) | Deserialize a sealed object |

Configuration

| Export | Description | |--------|-------------| | UploadOptions | Upload config — dataShards, parityShards, maxInflight, slabDataSize() | | DownloadOptions | Download config — maxInflight | | DownloadConfig | Parallel download config — workers, range, maxInflight | | StreamingUpload | Handle for a streaming upload — pushChunk(data), promise |

License

MIT