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

stream402-sdk

v0.1.0

Published

Stream402 SDK - Integrate x402 payment protocol into your applications

Downloads

3

Readme

Stream402 SDK

A TypeScript SDK for integrating Stream402 payment protocol into your applications. Stream402 enables monetization of digital content using Solana payments via the x402 protocol.

Installation

npm install @stream402/sdk

Quick Start

1. Discover an Asset

Check if an asset requires payment:

import { discover } from "@stream402/sdk";

const result = await discover("https://example.com/api/asset/123");

if (result.type === "free") {
  // Asset is free, use the URL directly
  console.log("Free asset:", result.url);
} else {
  // Payment required
  console.log("Payment required:", result.challenge);
  console.log("Amount:", result.challenge.amount, result.challenge.currency);
}

2. Pay and Fetch

Complete payment flow and get access to the resource:

import { payAndFetch } from "@stream402/sdk";
import { useWallet } from "@solana/wallet-adapter-react";

function MyComponent() {
  const wallet = useWallet();

  const handlePayAndFetch = async () => {
    try {
      const result = await payAndFetch(
        "https://example.com/api/asset/123",
        wallet
      );

      console.log("Download URL:", result.downloadUrl);
      console.log("Expires at:", new Date(result.expiresAt));

      // Use the download URL to access the resource
      window.open(result.downloadUrl, "_blank");
    } catch (error) {
      console.error("Payment failed:", error);
    }
  };

  return <button onClick={handlePayAndFetch}>Pay & Download</button>;
}

3. Upload Asset

Upload an asset as a content provider:

import { uploadAsset } from "@stream402/sdk";
import { useWallet } from "@solana/wallet-adapter-react";

function UploadComponent() {
  const wallet = useWallet();

  const handleUpload = async (file: File) => {
    try {
      const result = await uploadAsset(
        file,
        {
          title: "My Image",
          price: 0.01, // USDC
          tags: ["nature", "landscape"],
          description: "A beautiful landscape image",
        },
        wallet
      );

      console.log("Asset uploaded:", result.assetId);
      console.log("Asset URL:", result.url);
    } catch (error) {
      console.error("Upload failed:", error);
    }
  };

  return (
    <input
      type="file"
      onChange={(e) => {
        const file = e.target.files?.[0];
        if (file) handleUpload(file);
      }}
    />
  );
}

API Reference

discover(assetUrl: string): Promise<DiscoverResult>

Fetches an asset URL and returns either free access or a payment challenge.

Parameters:

  • assetUrl - Full URL to the asset (e.g., "https://example.com/api/asset/123")

Returns:

  • { type: "free", url: string } - Asset is free to access
  • { type: "payment_required", challenge: PaymentChallenge } - Payment required

Example:

const result = await discover("https://example.com/api/asset/123");

payAndFetch(assetUrl: string, walletAdapter: WalletAdapter, connection?: Connection): Promise<PaymentResult>

Completes the full payment flow and returns the resource.

Parameters:

  • assetUrl - Full URL to the asset
  • walletAdapter - Solana wallet adapter from @solana/wallet-adapter-react
  • connection - Optional Solana connection (defaults to devnet/mainnet based on challenge)

Returns:

  • { accessToken: string, downloadUrl: string, expiresAt: number }

Example:

const result = await payAndFetch(assetUrl, wallet);
// Use result.downloadUrl to access the resource

uploadAsset(file: File, meta: AssetMetadata, walletAdapter?: WalletAdapter, baseUrl?: string): Promise<UploadResponse>

Uploads an asset to Stream402.

Parameters:

  • file - File to upload
  • meta - Asset metadata:
    • title: string - Asset title
    • price: number | string - Price in USDC
    • recipient?: string - Recipient wallet address (optional, uses wallet if not provided)
    • tags?: string[] - Tags for searchability
    • description?: string - Asset description
  • walletAdapter - Optional wallet adapter (used for recipient if not provided)
  • baseUrl - Optional base URL of Stream402 API (defaults to current origin)

Returns:

  • { assetId: string, title: string, price: number, url: string, thumbnailUrl?: string }

Example:

const result = await uploadAsset(file, {
  title: "My Image",
  price: 0.01,
  tags: ["nature"],
}, wallet);

Types

PaymentChallenge

interface PaymentChallenge {
  version: string;
  network: string;
  currency: string;
  decimals: number;
  amount: number;
  mint: string;
  recipient: string;
  expiresAt: number;
  assetId: string;
  paymentRequestToken: string;
  description?: string;
  metadata?: Record<string, unknown>;
}

PaymentResult

interface PaymentResult {
  accessToken: string;
  downloadUrl: string;
  expiresAt: number;
}

AssetMetadata

interface AssetMetadata {
  title: string;
  price: number | string;
  recipient?: string;
  tags?: string[];
  description?: string;
}

Examples

React Component Example

import React, { useState } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
import { discover, payAndFetch } from "@stream402/sdk";

function AssetViewer({ assetUrl }: { assetUrl: string }) {
  const wallet = useWallet();
  const [status, setStatus] = useState<"loading" | "free" | "payment_required" | "paid">("loading");
  const [downloadUrl, setDownloadUrl] = useState<string>("");

  useEffect(() => {
    checkAsset();
  }, [assetUrl]);

  const checkAsset = async () => {
    try {
      const result = await discover(assetUrl);
      if (result.type === "free") {
        setStatus("free");
        setDownloadUrl(result.url);
      } else {
        setStatus("payment_required");
      }
    } catch (error) {
      console.error("Failed to discover asset:", error);
    }
  };

  const handlePay = async () => {
    if (!wallet.connected) {
      await wallet.connect();
    }

    try {
      const result = await payAndFetch(assetUrl, wallet);
      setStatus("paid");
      setDownloadUrl(result.downloadUrl);
    } catch (error) {
      console.error("Payment failed:", error);
    }
  };

  return (
    <div>
      {status === "loading" && <p>Loading...</p>}
      {status === "free" && <a href={downloadUrl}>Download</a>}
      {status === "payment_required" && (
        <button onClick={handlePay}>Pay to Access</button>
      )}
      {status === "paid" && <a href={downloadUrl}>Download</a>}
    </div>
  );
}

Node.js Example

import { discover, payAndFetch } from "@stream402/sdk";
import { Connection, Keypair } from "@solana/web3.js";
import { NodeWalletAdapter } from "@solana/wallet-adapter-wallets";

// Create a wallet adapter from a keypair
const keypair = Keypair.fromSecretKey(/* your secret key */);
const wallet = new NodeWalletAdapter(keypair);
const connection = new Connection("https://api.devnet.solana.com");

// Discover and pay
const result = await discover("https://example.com/api/asset/123");
if (result.type === "payment_required") {
  const paymentResult = await payAndFetch(
    "https://example.com/api/asset/123",
    wallet,
    connection
  );
  console.log("Download URL:", paymentResult.downloadUrl);
}

Requirements

  • Node.js 18+
  • TypeScript 5+
  • Solana wallet adapter (for payment functionality)

License

MIT

Support

For issues and questions, please visit Stream402 GitHub.