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

nostr-app-storage

v0.1.0

Published

Nostr storage library implementing NIP-60 wallet storage, NIP-78 settings sync, and NIP-42 relay authentication.

Readme

nostr-app-storage

A TypeScript/JavaScript library for storing application data on Nostr relays. Provides encrypted backup, cross-device sync, and decentralized data storage.

Features

  • NIP-60 Cashu Wallet Storage: Encrypted wallet proofs and transaction history
  • NIP-78 Application Settings: Cross-device settings synchronization
  • NIP-42 Relay Authentication: Secure access to auth-required relays
  • Automatic Chunking: Large data automatically split using nostr-chunked-events
  • NIP-44 Encryption: All content encrypted to owner's pubkey
  • Local-First: IndexedDB caching for offline access

Installation

npm install nostr-app-storage nostr-tools

Quick Start

import { initAppStorage } from 'nostr-app-storage';

const storage = await initAppStorage({
  pubkey: myPubkeyHex,
  relays: ['wss://relay.damus.io', 'wss://nos.lol'],
  signer: mySigner,        // EventSigner for signing events
  compression: true,       // Enable gzip for large data
  settingsTag: 'myapp:settings',
});

// Settings
const settings = await storage.settings.get();
await storage.settings.save({ theme: 'dark', language: 'en' });
await storage.settings.sync();

// Wallet
await storage.wallet.storeProofs(proofData, mintUrl, 'default-wallet');
const proofs = await storage.wallet.getProofs('default-wallet');

// Cleanup
await storage.close();

API Reference

initAppStorage(options)

Factory function that creates an AppStorage instance.

interface AppStorageOptions {
  pubkey: string;              // Your Nostr public key (hex)
  relays: string[];            // Relay URLs
  signer: EventSigner;         // For signing events
  compression?: boolean;       // Enable gzip compression
  settingsTag?: string;        // Custom d-tag for settings (default: 'nostr-app:settings')
  settingsEncrypted?: boolean; // Encrypt settings on relay
}

Settings API

// Get current settings (local-first, instant)
const settings = await storage.settings.get<MySettings>();

// Save settings (saves locally + syncs to relay)
await storage.settings.save({ theme: 'dark' });

// Sync with relay (fetch + merge)
const result = await storage.settings.sync();
// result.source: 'local' | 'remote' | 'unchanged'

// Listen for changes from other devices
storage.settings.onChange((newSettings, source) => {
  console.log('Settings changed from', source);
});

// Get sync status
const status = await storage.settings.getSyncStatus();

Wallet API

// Store proofs
await storage.wallet.storeProofs(proofData, mintUrl, walletDTag);

// Get proofs
const proofs = await storage.wallet.getProofs(walletDTag);

// Record transaction
await storage.wallet.recordTransaction({
  direction: 'in',
  txType: 'voucher_received',
  amount: 1000,
  counterparty: senderPubkey,
  timestamp: Date.now(),
});

// Get transaction history
const transactions = await storage.wallet.getTransactions({ limit: 50 });

// Publish wallet state to relay (auto-chunks large wallets)
await storage.wallet.publishWalletState(walletState);

// Restore wallet from relay
const result = await storage.wallet.fetchWalletState();

NIP-42 Authentication

import { Nip42Auth, createAuthenticatedConnection } from 'nostr-app-storage';

// Set global credentials
Nip42Auth.setCredentials({ pubkey: myPubkey, privateKey: myPrivateKey });
// Or use a signer
Nip42Auth.setSigner(mySigner);

// Create authenticated WebSocket
const conn = await createAuthenticatedConnection({
  relayUrl: 'wss://relay.example.com',
  pubkey: myPubkey,
  signer: mySigner,
  timeout: 10000,
  onReady: (ws) => console.log('Authenticated!'),
});

// conn.ws - WebSocket instance
// conn.authenticated - boolean
// conn.close() - cleanup

Low-Level APIs

SettingsSync

import { SettingsSync } from 'nostr-app-storage';

const settingsSync = new SettingsSync({
  pubkey: myPubkey,
  relays: ['wss://relay.example.com'],
  dTag: 'myapp:settings',
  encrypted: false,
  signer: mySigner,
  compression: true,
  chunkThreshold: 350000,
});

await settingsSync.init();
await settingsSync.saveSettings({ theme: 'dark' });
const result = await settingsSync.sync();

WalletStateSync

import { WalletStateSync } from 'nostr-app-storage';

const walletSync = new WalletStateSync({
  pubkey: myPubkey,
  signer: mySigner,
  relays: ['wss://relay.example.com'],
  crypto: myCrypto,
  compression: true,
});

await walletSync.publishWalletState({ tokens: [...], history: [...] });
const result = await walletSync.fetchWalletState();

Event Builders

import { Nip60EventBuilder, SettingsEventBuilder } from 'nostr-app-storage';

// Wallet events
const walletBuilder = new Nip60EventBuilder();
const walletEvent = walletBuilder.buildWalletEvent({
  dTag: 'my-wallet',
  name: 'Main Wallet',
  unit: 'sat',
  mints: ['https://mint.example.com'],
}, myPubkey);

// Settings events
const settingsBuilder = new SettingsEventBuilder();
const settingsEvent = settingsBuilder.buildSettingsEvent({
  dTag: 'myapp:settings',
  settings: { theme: 'dark' },
}, myPubkey);

Event Kinds

| Kind | Description | |------|-------------| | 17375 | Wallet Metadata (Parameterized Replaceable) | | 7375 | Proof Storage (Regular Event) | | 7376 | Transaction History (Regular Event) | | 37375 | Wallet State (Parameterized Replaceable, Chunked) | | 30078 | Application Settings (Parameterized Replaceable) | | 22242 | AUTH Event (NIP-42) |

Conflict Resolution

Settings sync uses a last-write-wins strategy based on timestamps:

| Scenario | Resolution | |----------|------------| | Only local exists | Push to relay | | Only remote exists | Save locally | | Both exist, remote newer | Use remote | | Both exist, local newer | Use local |

Custom merge functions can be provided:

const result = await storage.settings.sync((local, remote) => {
  // Custom merge logic
  return {
    settings: { ...local.settings, ...remote.settings },
    source: 'merged'
  };
});

Large Data Handling

The library automatically handles large data using nostr-chunked-events:

  • Wallet states > 350KB are automatically chunked
  • Settings > 350KB are automatically chunked
  • Compression reduces size before chunking (when enabled)
  • Reassembly is automatic when fetching

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type {
  AppStorage,
  AppStorageOptions,
  SettingsSyncResult,
  WalletState,
  TransactionRecord,
  CashuProof,
} from 'nostr-app-storage';

Dependencies

  • nostr-tools >= 2.0.0 (peer dependency)
  • nostr-chunked-events ^0.1.0
  • idb ^7.0.0

License

MIT