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

@nodeflow-network/nodeflow-api

v1.0.1

Published

API client for NodeFlow SDK

Readme

NodeFlow API

NodeFlow API is the API client for interacting with NodeFlow backend services, enabling asset bridging between EVM chains and the Lightning Network. This documentation will help you build cross-chain transfer functionality from scratch.

Installation

yarn add @nodeflow-network/nodeflow-api
# or
npm install @nodeflow-network/nodeflow-api

Core Concepts

Before starting development, you need to understand these core concepts:

| Concept | Description | | :--- | :--- | | Chain ID | Unique identifier for an EVM chain. e.g., 84532 (Base Sepolia), 8453 (Base Mainnet) | | Pair | Asset trading pair that defines the mapping between Lightning Network asset and EVM Token | | Pair ID | Unique identifier for a trading pair, returned by getPairs API | | Asset | Lightning Network side asset (e.g., Taproot Asset USDT) | | Token | EVM chain side token (e.g., ERC20 USDT) | | LSP | Liquidity Service Provider, responsible for executing cross-chain transfers | | Hashlock | Hash lock in HTLC (Hash Time-Locked Contract), ensures atomic swap security |

API Environments

| Environment | Base URL | | :--- | :--- | | Development | <API_BASE_URL> | | Production | (Contact support) |


Quick Start

Step 1: Initialize Client

import { NFApi } from '@nodeflow-network/nodeflow-api';

const client = new NFApi({
  baseURL: '<API_BASE_URL>',
  edgeBaseURL: '<EDGE_API_BASE_URL>', // Optional: for Edge API
  onAuthError: (error) => {
    // Called on 401 responses (token expired/invalid/revoked)
    // Clear local auth state and prompt re-login
    console.log('Auth error, please re-login');
  }
});

// Available APIs:
// - client.chain.*  (Bridge operations)
// - client.edge.*   (Edge node operations - coming soon)

Step 2: Authenticate (SIWE)

Write operations (signature, toLightning, toEVM, deposit) require JWT authentication via Sign In With Ethereum (SIWE).

import { SiweMessage } from 'siwe';

// 1. Get a one-time nonce from the server
const nonceRes = await client.chain.getNonce();
const nonce = nonceRes.data.nonce; // Server-generated, single-use, expires in 5 minutes

// 2. Construct SIWE message with server nonce
const message = new SiweMessage({
  domain: window.location.host,
  address: walletAddress,
  statement: 'Sign in with Ethereum to Astra Bridge',
  uri: window.location.origin,
  version: '1',
  chainId: chainId,
  nonce: nonce,
  issuedAt: new Date().toISOString(),
  expirationTime: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
});
const messageStr = message.prepareMessage();

// 3. Sign with wallet (e.g., wagmi signMessageAsync)
const signature = await signMessageAsync({ message: messageStr });

// 4. Login and set token
const res = await client.chain.login({ message: messageStr, signature });
if (res.code === 200) {
  client.setToken(res.data.token);
  // Token is now auto-injected into all subsequent requests
  // Store res.data.token and res.data.exp for session persistence
}

// 5. Logout (revokes token server-side)
await client.chain.logout();
client.clearToken();

Token Management:

| Method | Description | | :--- | :--- | | client.setToken(token) | Set JWT token for all requests (both main and edge) | | client.clearToken() | Clear JWT token from all request clients |

Public vs Protected Endpoints:

| Public (no token needed) | Protected (token required) | | :--- | :--- | | getContractConfig, getPairs, getPairInfo | getSignature, evmToLightning | | getTransaction, getAssetPayReq | lightningToEVM, toDeposit | | bridgeLimitStatus, getNonce, login | logout |

Step 3: Get Contract Configuration

Before any operation, get the contract configuration. This returns all supported chains and their contract addresses.

const configRes = await client.chain.getContractConfig();
const config = configRes.data;
// Returns supported chains, contract addresses, and ABIs

Step 4: Get Trading Pairs

Select a chainId and get the supported trading pairs:

const configRes = await client.chain.getContractConfig();
const chainId = Object.keys(configRes.data)[0]; // Use the first supported chain
const pairsResult = await client.chain.getPairs({ chainId });
const pair = pairsResult.data.pairs[0];
const pairId = pair.pairId;

Step 5: Get Pair Details

Get fees, limits, and other configuration:

const pairInfoRes = await client.chain.getPairInfo({ chainId, pairId });
const pairInfo = pairInfoRes.data;
// Returns fees, limits, LSP address, time locks

Bridge Flow Overview

How Lightning → EVM Works (Withdraw)

User sends BTC via Lightning to receive tokens on an EVM chain.

┌─────────────────────────────────────────────────────────────────────────────┐
│                    Lightning → EVM (Withdraw) Flow                          │
└─────────────────────────────────────────────────────────────────────────────┘

    User                         SDK / App                        LSP Node
      │                              │                                │
      │  1. Enter amount             │                                │
      ├─────────────────────────────►│                                │
      │                              │                                │
      │                              │  2. Request Quote & Invoice    │
      │                              ├───────────────────────────────►│
      │                              │  ◄── Return LN Invoice         │
      │                              │                                │
      │  3. Display Invoice          │                                │
      ◄──────────────────────────────│                                │
      │                              │                                │
      │  4. User pays via LN Wallet  │                                │
      ├──────────────────────────────┼───────────────────────────────►│
      │                              │                                │
      │                              │     5. Trigger Smart Contract  │
      │                              │  ◄──────────────────────────────│
      │                              │                                │
      │  6. Tokens received!         │                                │
      ◄──────────────────────────────│                                │

How EVM → Lightning Works (Deposit)

User pays with EVM tokens to pay a Lightning Invoice.

┌─────────────────────────────────────────────────────────────────────────────┐
│                    EVM → Lightning (Deposit) Flow                           │
└─────────────────────────────────────────────────────────────────────────────┘

    User                         SDK / App                        LSP Node
      │                              │                                │
      │  1. Paste LN Invoice         │                                │
      ├─────────────────────────────►│                                │
      │                              │                                │
      │  2. Show detailed quote      │                                │
      ◄──────────────────────────────│                                │
      │                              │                                │
      │  3. Approve & Deposit Tokens │                                │
      ├─────────────────────────────►│                                │
      │                              │                                │
      │                              │  4. Lock assets in Contract    │
      │                              ├───────────────────────────────►│
      │                              │                                │
      │                              │  5. Pay User's LN Invoice      │
      │                              │  ◄──────────────────────────────│
      │                              │                                │
      │  6. Invoice paid!            │                                │
      ◄──────────────────────────────│                                │

Complete API Flow Guide

Flow 1: EVM → Lightning (Pay LN Invoice with EVM Tokens)

Use case: User has EVM tokens (e.g., USDT) and wants to pay a Lightning invoice.

┌─────────────────────────────────────────────────────────────────────────────┐
│                     EVM → Lightning Complete API Flow                       │
└─────────────────────────────────────────────────────────────────────────────┘

   User                          Your App                         NodeFlow API
    │                               │                                   │
    │  1. Paste LN Invoice          │                                   │
    ├──────────────────────────────►│                                   │
    │                               │                                   │
    │                               │  2. getAssetPayReq({              │
    │                               │       payReq: "lnbc...",          │
    │                               │       assetId: "f7ac99..."        │
    │                               │     })                            │
    │                               ├──────────────────────────────────►│
    │                               │  ◄── { amount, paymentHash }      │
    │                               │                                   │
    │                               │  3. getPairInfo({                 │
    │                               │       chainId: chainId,           │
    │                               │       pairId: "0x7966..."         │
    │                               │     })                            │
    │                               ├──────────────────────────────────►│
    │                               │  ◄── { lspAddress, fee, timeLock }│
    │                               │                                   │
    │  4. Approve Token             │                                   │
    │  ERC20.approve(               │                                   │
    │    spender: lspAddress,       │                                   │
    │    amount: tokenAmount        │                                   │
    │  )                            │                                   │
    ├──────────────────────────────►│                                   │
    │                               │                                   │
    │  5. Deposit to Bridge         │                                   │
    │  Bridge.deposit({             │                                   │
    │    hashlock: paymentHash,     │                                   │
    │    toAddr: lspAddress,        │                                   │
    │    pairId: "0x7966...",       │                                   │
    │    amount: tokenAmount,       │                                   │
    │    timeLock: 3600,            │                                   │
    │    fee: toAssetBaseFee        │                                   │
    │  })                           │                                   │
    ├──────────────────────────────►│                                   │
    │                               │                                   │
    │                               │  6. evmToLightning({              │
    │                               │       pairId: "0x7966...",        │
    │                               │       chainId: chainId,           │
    │                               │       amount: tokenAmount,        │
    │                               │       lnInvoice: "lnbc...",       │
    │                               │       depositTx: "0xabc..."       │
    │                               │     })                            │
    │                               ├──────────────────────────────────►│
    │                               │  ◄── { status: "success" }        │
    │                               │                                   │
    │  7. ✅ Invoice Paid!           │                                   │
    ◄───────────────────────────────│                                   │

Code Implementation

Prerequisite based on viem/wagmi:

import { createWalletClient, custom, parseUnits } from 'viem';
import { baseSepolia } from 'viem/chains';
import { NFApi } from '@nodeflow-network/nodeflow-api';

const client = new NFApi({ baseURL: '...' });
const walletClient = createWalletClient({ chain: baseSepolia, transport: custom(window.ethereum) });
const [address] = await walletClient.requestAddresses();

Step-by-Step Logic:

// 1. Get Config & Pair
const { data: config } = await client.chain.getContractConfig();
const chainId = Object.keys(config)[0]; // Use the first available chain
const pair = (await client.chain.getPairs({ chainId })).data.pairs[0];
const pairInfo = await client.chain.getPairInfo({ chainId, pairId: pair.pairId });

// 2. Check Rate Limit
const limitStatus = await client.chain.bridgeLimitStatus({ address });
if (!limitStatus.data.isAllowed) {
  const minutes = Math.ceil(limitStatus.data.remainingSeconds / 60);
  throw new Error(`Rate limited. Wait ${minutes} minute(s).`);
}

// 3. Parse Invoice & Validate Amount
const lnInvoice = "lnbc..."; // User input
const invoiceData = await client.chain.getAssetPayReq({ payReq: lnInvoice, assetId: pair.asset.assetId });
const assetAmount = Number(invoiceData.data.amount) / (10 ** pair.asset.decimal);

// Validate against limits from pairInfo
if (assetAmount < pairInfo.data.min) {
  throw new Error(`Amount below minimum: ${pairInfo.data.min}`);
}
if (assetAmount > pairInfo.data.max) {
  throw new Error(`Amount exceeds maximum: ${pairInfo.data.max}`);
}

// Check channel liquidity
if (pairInfo.data.effectiveSatsBalance < pairInfo.data.satsCapacity * 0.1) {
  throw new Error("Channel liquidity too low");
}

// 4. Calculate Token Amount (Asset Decimal 8 -> Token Decimal 18)
const tokenAmount = BigInt(invoiceData.data.amount) * BigInt(10 ** pair.token.decimal) / BigInt(10 ** pair.asset.decimal);

// 5. Approve Token (ERC20)
const tokenAbi = config[chainId].USDT.abi;
await walletClient.writeContract({
  address: pair.token.address,
  abi: tokenAbi,
  functionName: 'approve',
  args: [pairInfo.data.lspAddress, tokenAmount],
  account: address
});

// 6. Deposit to Bridge
const bridgeAbi = config[chainId].Bridge.abi;
const depositTx = await walletClient.writeContract({
  address: config[chainId].Bridge.address,
  abi: bridgeAbi,
  functionName: 'deposit',
  args: [
    invoiceData.data.paymentHash,       // hashlock (from invoice)
    pairInfo.data.lspAddress,           // toAddr
    pair.pairId,                        // pairId
    tokenAmount,                        // amount
    pairInfo.data.evm2LightningDeltaSecond, // timeLock
    pairInfo.data.toAssetBaseFee,       // fee
    '0x',                               // signature (not needed for EVM -> LN)
    '0x00'                              // nodePubkey (placeholder)
  ],
  account: address
});

// 7. Notify Backend to Pay Invoice
await client.chain.evmToLightning({
  pairId: pair.pairId,
  chainId: chainId,
  amount: tokenAmount.toString(),
  lnInvoice: lnInvoice,
  depositTx: depositTx
});

Flow 2: Lightning → EVM (Receive EVM Tokens by Paying LN)

Use case: User wants to receive EVM tokens by paying a Lightning invoice.

┌─────────────────────────────────────────────────────────────────────────────┐
│                     Lightning → EVM Complete API Flow                       │
└─────────────────────────────────────────────────────────────────────────────┘

   User                          Your App                         NodeFlow API
    │                               │                                   │
    │  1. Enter desired amount      │                                   │
    ├──────────────────────────────►│                                   │
    │                               │                                   │
    │                               │  2. getSignature({                │
    │                               │       chainId: chainId,           │
    │                               │       amount: 1000,               │
    │                               │       pairId: "0x7966..."         │
    │                               │     })                            │
    │                               ├──────────────────────────────────►│
    │                               │  ◄── { hashlock, signature,       │
    │                               │        nodePubKey }               │
    │                               │                                   │
    │  3. Deposit to Bridge         │                                   │
    │  Bridge.deposit({             │                                   │
    │    hashlock: hashlock,        │                                   │
    │    toAddr: lspAddress,        │                                   │
    │    pairId: "0x7966...",       │                                   │
    │    amount: tokenAmount,       │                                   │
    │    timeLock: 1800,            │                                   │
    │    fee: toTokenBaseFee,       │                                   │
    │    signature: signature       │                                   │
    │  })                           │                                   │
    ├──────────────────────────────►│                                   │
    │                               │                                   │
    │                               │  4. lightningToEVM({              │
    │                               │       pairId: "0x7966...",        │
    │                               │       chainId: chainId,           │
    │                               │       hashlock: hashlock,         │
    │                               │       amount: 1000,               │
    │                               │       depositTx: "0xabc..."       │
    │                               │     })                            │
    │                               ├──────────────────────────────────►│
    │                               │  ◄── { invoice: "lnbc..." }       │
    │                               │                                   │
    │  5. Display Invoice QR        │                                   │
    ◄───────────────────────────────│                                   │
    │                               │                                   │
    │  6. User pays via LN Wallet   │                                   │
    ├───────────────────────────────┼──────────────────────────────────►│
    │                               │                                   │
    │                               │  (Backend detects payment,        │
    │                               │   unlocks tokens on-chain)        │
    │                               │                                   │
    │  7. ✅ Tokens Received!        │                                   │
    ◄───────────────────────────────│                                   │

Code Implementation

Step-by-Step Logic:

// Assume config, chainId, pair, pairInfo are already fetched (see Flow 1)

// 1. User inputs desired asset amount (e.g., 100 in asset units)
const assetAmount = 100; // In asset decimal units (e.g., sats for BTC)

// 2. Check Rate Limit
const limitStatus = await client.chain.bridgeLimitStatus({ address });
if (!limitStatus.data.isAllowed) {
  const minutes = Math.ceil(limitStatus.data.remainingSeconds / 60);
  throw new Error(`Rate limited. Wait ${minutes} minute(s).`);
}

// 3. Validate Amount against limits
if (assetAmount < pairInfo.data.min) {
  throw new Error(`Amount below minimum: ${pairInfo.data.min}`);
}
if (assetAmount > pairInfo.data.max) {
  throw new Error(`Amount exceeds maximum: ${pairInfo.data.max}`);
}

// 4. Get Signature from LSP
const sigRes = await client.chain.getSignature({
  chainId: chainId,
  amount: assetAmount,
  pairId: pair.pairId
});
const sigData = sigRes.data;
// Response: { hashlock, signature, lspNodePubKey, amtInContract, deltaSecond, fee, lspAddress }

// 5. Deposit to Bridge (On-Chain)
// IMPORTANT: Use amtInContract from signature response, NOT calculated tokenAmount
const depositAmount = BigInt(sigData.amtInContract);

const bridgeAbi = config[chainId].Bridge.abi;
const depositTx = await walletClient.writeContract({
  address: config[chainId].Bridge.address,
  abi: bridgeAbi,
  functionName: 'deposit',
  args: [
    sigData.hashlock,                   // hashlock from LSP
    account.address,                     // toAddr (user's address - receives tokens)
    sigData.pairId,                     // pairId
    depositAmount,                      // amount (from signature response)
    BigInt(sigData.deltaSecond),        // timeLock
    sigData.fee,                        // fee
    sigData.signature,                  // signature (REQUIRED for LN -> EVM)
    sigData.lspNodePubKey               // nodePubkey (REQUIRED)
  ],
  account: address
});

// 6. Get Lightning Invoice to Pay
const result = await client.chain.lightningToEVM({
  pairId: pair.pairId,
  chainId: chainId,
  hashlock: sigData.hashlock,
  amount: sigData.amtInContract,        // Use amtInContract, not assetAmount
  depositTx: depositTx
});

console.log("Pay this Invoice:", result.data.invoice);
// User pays the invoice with their Lightning wallet
// After payment, LSP unlocks tokens on-chain automatically

API Reference

Chain API - Authentication Methods

| Method | Parameters | Returns | Description | | :--- | :--- | :--- | :--- | | chain.getNonce() | - | { nonce } | Get a one-time server nonce for SIWE login (expires in 5 min) | | chain.login({ message, signature }) | SIWE message string, wallet signature | { token, user, exp, jti } | Login with SIWE signature, returns JWT | | chain.logout() | - | { message } | Revoke current JWT token server-side |

Usage Example:

// Get nonce, then login
const { data: { nonce } } = await client.chain.getNonce();
// ... construct SIWE message with nonce, sign it ...
const res = await client.chain.login({ message: siweMessage, signature: walletSig });
client.setToken(res.data.token);

// Logout
await client.chain.logout();
client.clearToken();

Chain API - Configuration Methods

| Method | Parameters | Returns | Description | | :--- | :--- | :--- | :--- | | chain.getContractConfig() | - | { [chainId]: { Bridge, Token... } } | Get all supported chains and contract configs | | chain.getPairs({ chainId }) | chainId: number | { pairs: [...] } | Get trading pairs for a chain | | chain.getPairInfo({ chainId, pairId }) | chainId, pairId | { lspAddress, min, max, fee... } | Get pair details |

Usage Example:

const config = await client.chain.getContractConfig();
const pairs = await client.chain.getPairs({ chainId: 84532 });
const pairInfo = await client.chain.getPairInfo({ chainId: 84532, pairId: '0x7966...' });

Chain API - Transaction Methods

| Method | Parameters | Returns | Description | | :--- | :--- | :--- | :--- | | chain.getSignature({ chainId, amount, pairId }) | chainId, amount, pairId | { hashlock, signature } | Get signature for LN→EVM | | chain.evmToLightning({ pairId, chainId, amount, lnInvoice, depositTx }) | see details | { status } | Submit EVM→LN deposit | | chain.lightningToEVM({ pairId, chainId, hashlock, amount, depositTx }) | see details | { invoice } | Submit LN→EVM deposit | | chain.toDeposit({ chainId, pairId, depositArgs, signature, signerAddress }) | see details | { status } | Submit signed deposit |

Usage Example:

const signature = await client.chain.getSignature({ chainId: 84532, amount: 1000, pairId: '0x7966...' });
await client.chain.evmToLightning({ pairId, chainId, amount, lnInvoice, depositTx });
const result = await client.chain.lightningToEVM({ pairId, chainId, hashlock, amount, depositTx });

Chain API - Query Methods

| Method | Parameters | Returns | Description | | :--- | :--- | :--- | :--- | | chain.getTransaction({ hashlock }) | hashlock | { status, ... } | Query transaction status | | chain.getAssetPayReq({ payReq, assetId }) | payReq, assetId | { amount, paymentHash } | Parse and validate invoice | | chain.bridgeLimitStatus({ address }) | address | { isAllowed, remainingSeconds } | Check rate limit status |

Usage Example:

const tx = await client.chain.getTransaction({ hashlock: '0xabc...' });
const invoice = await client.chain.getAssetPayReq({ payReq: 'lnbc...', assetId: 'f7ac99...' });
const status = await client.chain.bridgeLimitStatus({ address: '0x123...' });

Edge API

The Edge API provides advanced Lightning Network edge node functionality.

| Method | Parameters | Returns | Description | | :--- | :--- | :--- | :--- | | edge.connectNode(params) | node_key_url, node_type | { code, msg } | Connect to a peer node | | edge.buyLiquidity(params) | assetType, assetId, amount, nodeKeyUrl, payType | { data: { invoice... } } | Purchase inbound liquidity | | edge.liquidityOut(params) | assetType, assetId, amount, nodeKey, payType | { data: { invoice... } } | Purchase outbound liquidity | | edge.getLiquidityRecords(params) | current, size, nodeKey | { data: { records... } } | Get liquidity order history | | edge.getCoinList() | - | { data: [...] } | Get supported coin list | | edge.getAssetList() | - | { data: [...] } | Get asset list | | edge.getPublicInfo() | - | { data: [...] } | Get edge node public info |

Usage Example:

// 1. Connect Node
await client.edge.connectNode({
  node_key_url: "[email protected]:9735",
  node_type: "LND"
});

// 2. Get Public Info
const publicInfo = await client.edge.getPublicInfo();
console.log(publicInfo.data);

// 2. Buy Liquidity (Inbound)
const inResult = await client.edge.buyLiquidity({
  assetType: "TAPROOT",
  assetId: "f7ac99...",
  amount: "100000",
  nodeKeyUrl: "[email protected]:9735",
  payType: "TAPROOT"
});

// 3. Buy Liquidity (Outbound)
const outResult = await client.edge.liquidityOut({
  assetType: "TAPROOT",
  assetId: "f7ac99...",
  amount: "100000",
  nodeKey: "03b24a...",
  payType: "TAPROOT"
});

// 4. Get Records
const records = await client.edge.getLiquidityRecords({
  current: 1,
  size: 10,
  nodeKey: "03b24a..."
});

// 5. Get Coin List
const coinList = await client.edge.getCoinList();
console.log(coinList.data);

// 6. Get Asset List
const assetList = await client.edge.getAssetList();
console.log(assetList.data);

FAQ

Q: How do I know which chainIds are supported?

Call getContractConfig(). The response object keys are the supported chainIds.

Q: Where do I get the pairId?

Call getPairs({ chainId }). Each pair object contains a pairId.

Q: How to handle failed transactions?

Use getTransaction({ hashlock }) to query transaction status and decide if refund is needed.


License

MIT