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

chunktech

v0.3.0

Published

On-chain file storage via chunked transactions for EVM chains

Readme

ChunkTech

On-chain file storage via chunked transactions for EVM chains.

Store and retrieve files on Ethereum, Base, and Arbitrum using transaction calldata. Includes specialized support for censorship-resistant browser extension distribution.

Features

  • Chunk - Split files into 33.3KB pieces for on-chain storage
  • Send - Broadcast chunks as self-transfer transactions
  • Track - Monitor transaction confirmations
  • Reassemble - Reconstruct files from on-chain data
  • Encrypt - Optional X3DH encryption for private data
  • Cross-Chain - Store data on L2, pointer on mainnet
  • Extensions - Distribute Chrome/Firefox extensions via inscriptions

Installation

npm install chunktech viem

For encryption support:

npm install @noble/curves @noble/hashes

Quick Start

import { ChunkTech } from 'chunktech';
import { createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`);
const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(),
});

const ct = new ChunkTech({ walletClient });

// Upload
const result = await ct.upload(fileData, {
  onProgress: (sent, total) => console.log(`${sent}/${total}`),
});

// Download
const downloaded = await ct.download(result.txHashes);

Browser Extension Distribution

Distribute Chrome and Firefox extensions as on-chain inscriptions. The inscription itself is the installer - a self-contained HTML page that fetches extension data from L2 and offers downloads.

┌─────────────────────────────────────────────────────────┐
│  Inscription (Ethereum)                                 │
│                                                         │
│  Self-contained HTML that:                              │
│  ├── Shows extension info + download buttons            │
│  ├── Fetches chunks from Base via RPC                   │
│  ├── Reassembles + verifies SHA256                      │
│  └── Downloads as .zip (Chrome) or .xpi (Firefox)       │
│                                                         │
└─────────────────────────────────────────────────────────┘

Upload Extension

import { ExtensionUploader } from 'chunktech';
import { createWalletClient, http } from 'viem';
import { base, mainnet } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';
import { readFileSync } from 'fs';

const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`);

const uploader = new ExtensionUploader({
  keyChain: 'ethereum',     // Inscription lives here (1 tx)
  dataChain: 'base',        // Extension data lives here (cheap)
  keyWalletClient: createWalletClient({
    account,
    chain: mainnet,
    transport: http(),
  }),
  dataWalletClient: createWalletClient({
    account,
    chain: base,
    transport: http(),
  }),
});

const result = await uploader.upload({
  name: 'My Extension',
  version: '1.0.0',
  developer: 'vitalik.eth',
  description: 'A censorship-resistant browser extension',
  homepage: 'https://myextension.xyz',
  chrome: readFileSync('dist/chrome.zip'),
  firefox: readFileSync('dist/firefox.xpi'),
}, {
  onProgress: (phase, sent, total) => {
    console.log(`${phase}: ${sent}/${total}`);
  },
});

console.log('Inscription TX:', result.inscriptionTxHash);
// View at: https://ethscriptions.com/ethscriptions/0x...

What Users See

The inscription renders as a download page:

╔═══════════════════════════════════════════════════╗
║         My Extension v1.0.0                       ║
║         vitalik.eth                               ║
╚═══════════════════════════════════════════════════╝

A censorship-resistant browser extension

┌─────────────────┐    ┌─────────────────┐
│  Chrome/Brave   │    │    Firefox      │
│   [Detected]    │    │                 │
│  [Download]     │    │  [Download]     │
│   142 KB        │    │   138 KB        │
└─────────────────┘    └─────────────────┘

Installation Instructions:
1. Download the extension
2. Unzip (Chrome) or keep as .xpi (Firefox)
3. Load in developer mode / Install from file

Why This Matters

  • Censorship-resistant - No app store can remove it
  • Immutable - Code is permanently on-chain
  • Verifiable - SHA256 verified on download
  • Self-contained - The inscription IS the installer
  • Multi-browser - Chrome, Brave, Edge, Firefox from one inscription

Cross-Chain Upload

Store bulk data on L2 (cheap), pointer on mainnet (durable):

import { CrossChainUploader } from 'chunktech';

const uploader = new CrossChainUploader({
  keyChain: 'ethereum',
  dataChain: 'base',
  keyWalletClient,
  dataWalletClient,
});

const result = await uploader.upload(fileData, {
  format: 'html',
  title: 'My File',
});

// result.keyTxHash = mainnet inscription (self-loading HTML)
// result.dataTxHashes = Base data chunks

API Reference

ChunkTech

Main class for single-chain uploads.

const ct = new ChunkTech({
  walletClient: WalletClient,  // viem wallet
  publicClient?: PublicClient, // Optional
  chain?: Chain,               // Auto-detected
  rpcUrl?: string,             // Custom RPC
});

// Upload
const result = await ct.upload(data, {
  encrypt?: boolean,
  keys?: EncryptionKeys,
  recipients?: Recipient[],
  onProgress?: (sent, total) => void,
  confirmations?: number,
});

// Download
const result = await ct.download(txHashes, {
  keys?: EncryptionKeys,
  recipientId?: string,
});

ExtensionUploader

Specialized uploader for browser extensions.

const uploader = new ExtensionUploader({
  keyChain: 'ethereum' | 'sepolia',
  dataChain: 'base' | 'baseSepolia',
  keyWalletClient: WalletClient,
  dataWalletClient: WalletClient,
  keyRpcUrl?: string,
  dataRpcUrl?: string,
});

const result = await uploader.upload({
  name: string,
  version: string,
  developer: string,
  description?: string,
  homepage?: string,
  chrome?: Uint8Array,
  firefox?: Uint8Array,
}, {
  onProgress?: (phase, sent, total) => void,
  confirmations?: number,
});

CrossChainUploader

General-purpose cross-chain uploader with HTML loader.

const uploader = new CrossChainUploader({
  keyChain: ChainName,
  dataChain: ChainName,
  keyWalletClient: WalletClient,
  dataWalletClient: WalletClient,
});

const result = await uploader.upload(data, {
  format?: 'html' | 'json',
  title?: string,
  description?: string,
  mimeType?: string,
});

Low-Level Utilities

import {
  // Chunking
  chunkData,
  encodeChunk,
  decodeChunk,
  reassembleChunks,
  ChunkTracker,
  estimateChunks,

  // Sending
  sendChunk,
  sendChunks,
  sendChunksParallel,

  // Tracking
  waitForTransaction,
  waitForTransactions,
  TransactionMonitor,

  // Fetching
  fetchChunk,
  fetchChunks,
  assembleFromHashes,
  StreamingAssembler,

  // Encryption
  generateEncryptionKeys,
  deriveKeysFromSignature,
  encryptForRecipients,
  decryptForRecipient,
} from 'chunktech';

Encryption

Optional X3DH + AES-256-GCM encryption for private data.

import { generateEncryptionKeys } from 'chunktech';

const myKeys = await generateEncryptionKeys();

// Upload encrypted
await ct.upload(data, {
  encrypt: true,
  keys: myKeys,
  recipients: [
    { id: 'alice', bundle: aliceKeys.bundle },
  ],
});

// Download encrypted
const result = await ct.download(txHashes, {
  keys: myKeys,
  recipientId: 'sender',
});

Supported Chains

| Chain | ID | Use Case | |-------|-----|----------| | Ethereum | 1 | Inscriptions, durability | | Base | 8453 | Cheap data storage | | Arbitrum | 42161 | Cheap data storage | | Sepolia | 11155111 | Testing | | Base Sepolia | 84532 | Testing | | Arbitrum Sepolia | 421614 | Testing |

Cost Estimates

For a 500KB extension on Base:

Chunks: ~15 (at 33KB each)
Cost per chunk: ~$0.002
Total: ~$0.03

+ 1 Ethereum inscription: ~$2-5 (varies with gas)

How It Works

  1. Chunking - Files split into 33.3KB pieces with metadata (ID, part, total)
  2. Encoding - Each chunk → JSON → base64 → prefixed calldata
  3. Sending - Self-transfer transactions (to == from, value = 0)
  4. Storage - Calldata stored permanently in transaction history
  5. Retrieval - Fetch via eth_getTransactionByHash, decode, reassemble
  6. Verification - SHA256 hash checked after reassembly

On-Chain Viewer Pages

Create standalone HTML pages that fetch, verify, and display on-chain content. Perfect for:

  • NPM packages with auditable source
  • Browser extensions with install instructions
  • Any file needing public verification

Quick Inscribe

import { readFileSync } from 'fs';
import { createWalletClient, http, toHex } from 'viem';
import { base } from 'viem/chains';
import { createHash } from 'crypto';

const zipData = readFileSync('package.zip');
const base64 = zipData.toString('base64');
const sha256 = createHash('sha256').update(zipData).digest('hex');

const dataUri = `data:application/zip;base64,${base64}`;
const calldata = toHex(new TextEncoder().encode(dataUri));

const hash = await walletClient.sendTransaction({
  to: account.address,
  data: calldata,
});

console.log(`TX: ${hash}`);
console.log(`SHA256: ${sha256}`);

Viewer HTML

The viewer fetches from any RPC, verifies SHA256, and displays source:

┌─────────────────────────────────────────┐
│  MyPackage v1.0.0                       │
│                                         │
│  [Download]  [Verify On-Chain]          │
│                                         │
│  ┌─────────────────────────────────┐    │
│  │ README │ index.ts │ package.json│    │
│  ├─────────────────────────────────┤    │
│  │                                 │    │
│  │  // Source code displayed here  │    │
│  │                                 │    │
│  └─────────────────────────────────┘    │
└─────────────────────────────────────────┘

Key features:

  • Fetches tx via public RPC (no backend)
  • SHA256 verification on download
  • Source code tabs for auditing
  • Works offline once loaded

See skill.md for full implementation details.

Acknowledgments

  • calldata-rpc by @chopperdaddy - Decentralized RPC endpoint discovery via IPFS and ENS, used in the HTML loaders for reliable chain access.

License

MIT