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

@datafund/swarm-provenance

v0.5.0

Published

TypeScript SDK for Swarm Provenance - store and retrieve provenance data via the Swarm network

Readme

@datafund/swarm-provenance

npm version License: MIT

TypeScript SDK for storing and retrieving provenance data via the Swarm network.

Requirements

  • Node.js >= 18.0.0
  • viem >= 2.0.0 (optional, for blockchain anchoring only)

Installation

pnpm add @datafund/swarm-provenance

For blockchain anchoring features, also install viem:

pnpm add @datafund/swarm-provenance viem

For x402 paid gateway access (higher rate limits), also install:

pnpm add @datafund/swarm-provenance @x402/fetch @x402/evm viem

Quick Start

import { ProvenanceClient } from '@datafund/swarm-provenance';

const client = new ProvenanceClient();

// Upload data
const result = await client.upload('Hello, World!', {
  standard: 'my-provenance-v1',
});

console.log('Uploaded:', result.reference);

// Download data
const downloaded = await client.download(result.reference);
console.log('Content:', new TextDecoder().decode(downloaded.file));

x402 Payment Mode

By default, the SDK uses the free tier (X-Payment-Mode: free), which is rate-limited. For higher throughput, configure x402 automatic USDC payments:

import { ProvenanceClient } from '@datafund/swarm-provenance';
import { createWalletClient, http } from 'viem';
import { baseSepolia } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';
import { publicActions } from 'viem';

// Create a signer with readContract support
const wallet = createWalletClient({
  account: privateKeyToAccount('0x...'),
  chain: baseSepolia,
  transport: http(),
}).extend(publicActions);

const client = new ProvenanceClient({
  payment: { wallet },
});

// Requests that receive 402 responses are automatically paid via USDC
const result = await client.upload('Hello, World!');

Payment modes:

  • 'free' (default) — sends X-Payment-Mode: free header, rate-limited
  • 'none' — no payment header, gets raw 402 responses
  • { wallet } — automatic x402 USDC payments via @x402/fetch

Blockchain Anchoring

import { ChainClient, fromPrivateKey } from '@datafund/swarm-provenance/chain';

// Read-only (no wallet needed)
const chain = new ChainClient({ chain: 'base-sepolia' });
const exists = await chain.verifyOnChain(contentHash);
const record = await chain.getDataRecord(contentHash);

// With wallet (browser)
import { fromEip1193Provider } from '@datafund/swarm-provenance/chain';
const signer = await fromEip1193Provider(window.ethereum);
const chain = new ChainClient({ chain: 'base-sepolia', signer });
const result = await chain.anchor(contentHash, 'dataset');

// With private key (Node.js)
const signer = await fromPrivateKey('0x...', 'https://sepolia.base.org');
const chain = new ChainClient({ chain: 'base-sepolia', signer });
await chain.anchor(contentHash, 'dataset');

Features

  • Simple API: High-level upload() and download() methods handle the full workflow
  • Automatic stamp management: Acquires stamps from the pool automatically
  • Notary signing: Optional cryptographic signatures for data authenticity
  • Content verification: Automatic SHA256 hash verification on download
  • Blockchain anchoring: Register data hashes on-chain for immutable provenance
  • Browser + Node.js: Works in both environments with native fetch
  • TypeScript first: Full type definitions included

API

ProvenanceClient

const client = new ProvenanceClient({
  gatewayUrl?: string,      // default: https://provenance-gateway.datafund.io
  timeout?: number,         // default: 30000ms
  payment?: PaymentMode,    // default: 'free' (see x402 Payment Mode)
});

Upload

const result = await client.upload(content, {
  sign?: 'notary',                         // Enable notary signing
  standard?: string,                       // Provenance standard identifier
  stampId?: string,                        // Use existing stamp (skip pool)
  poolSize?: 'small' | 'medium' | 'large', // Pool size preset
  contentType?: string,                    // Content type
});

// Returns:
// {
//   reference: string,           // Swarm hash
//   metadata: ProvenanceMetadata,
// }

Download

const result = await client.download(reference, {
  verify?: boolean,  // Verify notary signature (default: true)
});

// Returns:
// {
//   file: Uint8Array,            // Decoded content
//   metadata: ProvenanceMetadata,
//   verified?: boolean,
//   signatures?: NotarySignature[],
// }

Other Methods

// Health check
await client.health(); // => boolean

// Notary info
await client.notaryInfo();
// => { enabled: boolean, available: boolean, address?: string }

// Pool status
await client.poolStatus();
// => { enabled: boolean, available: Record<string, number>, reserve: Record<string, number> }

// Acquire stamp directly
await client.acquireStamp('small');
// => { batchId: string, depth: number, sizeName: string, fallbackUsed: boolean }

Error Handling

import {
  ProvenanceError,
  GatewayConnectionError,
  StampError,
  NotaryError,
  VerificationError,
  PaymentError,
  PaymentConfigurationError,
  PaymentRateLimitError,
} from '@datafund/swarm-provenance';

try {
  await client.upload(content);
} catch (error) {
  if (error instanceof PaymentRateLimitError) {
    console.error('Rate limited, retry after:', error.retryAfterSeconds, 'seconds');
  } else if (error instanceof PaymentConfigurationError) {
    console.error('Missing @x402 packages:', error.message);
  } else if (error instanceof StampError) {
    console.error('Stamp acquisition failed:', error.message);
  } else if (error instanceof GatewayConnectionError) {
    console.error('Gateway error:', error.statusCode, error.message);
  }
}

Advanced Usage

Low-level utilities

import {
  buildMetadata,
  extractContent,
  verifyContentHash,
  sha256Hex,
  bytesToBase64,
  base64ToBytes,
} from '@datafund/swarm-provenance';

// Build metadata manually
const metadata = buildMetadata(content, {
  stampId: 'my-stamp',
  standard: 'v1',
});

// Extract and verify
const originalContent = extractContent(metadata);
const isValid = verifyContentHash(metadata);

Signature verification

import {
  verifySignature,
  verifyAllSignatures,
} from '@datafund/swarm-provenance';

const result = verifySignature(signature, metadata, expectedSigner);
// => { valid: boolean, dataHashValid: boolean, signerValid?: boolean }

Blockchain Anchoring (/chain)

The chain module provides on-chain data provenance via a DataProvenance smart contract. It uses viem as an optional peer dependency (see Installation).

ChainClient

import { ChainClient } from '@datafund/swarm-provenance/chain';

const chain = new ChainClient({
  chain: 'base-sepolia',     // or 'base' for mainnet, or a custom ChainPreset
  rpcUrl?: string,            // override RPC endpoint
  signer?: ChainSigner,       // required for write operations
});

Read Operations (no signer required)

// Check if a hash is registered on-chain
await chain.verifyOnChain(dataHash);  // => boolean

// Get full provenance record
await chain.getDataRecord(dataHash);
// => { dataHash, owner, timestamp, dataType, status, accessors, transformationLinks }

// Get all records owned by an address
await chain.getUserDataRecords('0x...');  // => string[]
await chain.getUserDataRecordsCount('0x...');  // => number
await chain.getUserDataRecordsPaginated('0x...', 0, 10);  // => string[]

// Check if an address has accessed a hash
await chain.hasAddressAccessed(dataHash, '0x...');  // => boolean

// Check delegate authorization
await chain.isAuthorizedDelegate(owner, delegate);  // => boolean

// Transformation links and parents (v2 contract)
await chain.getTransformationLinks(dataHash);
// => TransformationLink[] ({ newDataHash, description })
await chain.getTransformationParents(dataHash);  // => string[]
await chain.getChildHashes(dataHash);  // => string[]

// Traverse full provenance chain (BFS, bidirectional)
await chain.getProvenanceChain(dataHash, 10);
// => ChainProvenanceRecord[] — ancestors + descendants up to maxDepth

// Detect v2 contract support
await chain.supportsTransformationLinks();  // => boolean

// Health check and balance
await chain.healthCheck();  // => boolean (never throws)
await chain.getBalance();  // => { address, balanceWei, balanceEth, chain }

Write Operations (signer required)

// Anchor a data hash on-chain
const result = await chain.anchor(dataHash, 'dataset');
// => { txHash, blockNumber, gasUsed, explorerUrl, dataHash, dataType, owner }

// Anchor on behalf of another owner (operator only)
await chain.anchorFor(dataHash, 'dataset', ownerAddress);

// Record access
await chain.recordAccess(dataHash);
// => { txHash, blockNumber, gasUsed, explorerUrl, dataHash, accessor }

// Record 1-to-1 transformation
await chain.recordTransformation(originalHash, newHash, 'filtered PII');

// Record N-to-1 merge transformation (v2 contract)
await chain.mergeTransform(
  [sourceHash1, sourceHash2],
  mergedHash,
  'combined datasets',
  'merged',  // data type (default: 'merged')
);

// Set data status (ACTIVE=0, RESTRICTED=1, DELETED=2)
import { DataStatus } from '@datafund/swarm-provenance/chain';
await chain.setDataStatus(dataHash, DataStatus.RESTRICTED);

// Transfer ownership
await chain.transferOwnership(dataHash, newOwnerAddress);

// Manage delegates
await chain.setDelegate(delegateAddress, true);   // authorize
await chain.setDelegate(delegateAddress, false);  // revoke

// Batch operations
await chain.batchAnchor([
  { dataHash: hash1, dataType: 'dataset' },
  { dataHash: hash2, dataType: 'model' },
]);
await chain.batchRecordAccess([hash1, hash2]);
await chain.batchSetDataStatus([
  { dataHash: hash1, status: DataStatus.RESTRICTED },
]);

Signer Factories

import {
  fromEip1193Provider,
  fromPrivateKey,
  fromViemWalletClient,
} from '@datafund/swarm-provenance/chain';

// Browser wallet (MetaMask, etc.)
const signer = await fromEip1193Provider(window.ethereum);

// Private key (Node.js / scripts)
const signer = await fromPrivateKey('0x...', 'https://sepolia.base.org');

// Existing viem WalletClient
const signer = fromViemWalletClient(walletClient);

Chain Error Handling

import {
  ChainConnectionError,
  ChainTransactionError,
  DataNotRegisteredError,
  SignerRequiredError,
} from '@datafund/swarm-provenance/chain';

try {
  await chain.anchor(hash, 'dataset');
} catch (error) {
  if (error instanceof SignerRequiredError) {
    console.error('Connect a wallet first');
  } else if (error instanceof ChainTransactionError) {
    console.error('Transaction failed:', error.txHash);
  }
}

Supported Networks

| Network | Preset | Contract | |---------|--------|----------| | Base Sepolia (testnet) | base-sepolia | 0xD4a724CD7f5C4458cD2d884C2af6f011aC3Af80a | | Base (mainnet) | base | Not yet deployed |

Breaking Changes in v0.5.0

The v2 contract update changes the ChainProvenanceRecord type:

// Before (v0.4.x)
record.transformations  // string[]

// After (v0.5.0)
record.transformationLinks  // TransformationLink[] ({ newDataHash, description })

The ChainTransformation type is deprecated — use TransformationLink instead.

Demo App

A reference React app is available at examples/web-app/ with upload, download, notary signing, blockchain anchoring, merge transformations, and provenance chain traversal:

cd examples/web-app
pnpm install
pnpm dev

Open http://localhost:5173 to try the full workflow.

Development

# Install dependencies
pnpm install

# Build
pnpm build

# Unit tests
pnpm test

# Integration tests (requires gateway / Hardhat)
pnpm test:integration

# E2E tests (Playwright)
cd examples/web-app && pnpm test

# Type check
pnpm typecheck

# Lint
pnpm lint

Contributing

Contributions are welcome. Please open an issue first to discuss what you'd like to change.

  1. Fork the repo
  2. Create a feature branch from development (git checkout -b feature/my-feature development)
  3. Commit your changes
  4. Push and open a PR against development

All PRs to main require a review. See the development section for build and test commands.

Related Projects

License

MIT