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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@developers.cash/cash-pay-server-js

v0.15.3

Published

A Client-side and Server-side library for integrating with Cash Pay Server instances.

Downloads

11

Readme

Cash-Pay-Server-JS

Javascript/Node library for use with Cash Pay Server.

CashPayServer is a self-hostable NodeJS micro-service that can be used to handle BIP70 and JSON Payment Protocol invoices for Bitcoin Cash (BCH). This allows services to receive payments in BCH and attach arbitrary information to each transaction (e.g. Invoice Numbers, Order Details, etc).

CodePen Client-side Example

CodePen Example

Features:

  • BIP70 and JSON Payment Protocol Support
  • Default template renders in <div> container for easy integration (custom templates supported)
  • Websocket notifications (handle events on the client-side in real-time)
  • Webhook support (handle events in the backend - e.g. broadcasted, confirmed)
  • Exchange Rate calculation for most currencies (using Coinbase Exchange API)
  • OP_RETURN and custom script support via addOutput (BIP70 only)
  • Admin/Debugging Dashboard (https://admin.v1.pay.infra.cash/)

Documentation: https://developers-cash.github.io/cash-pay-server-js/

Quick Start

Include the cash-pay-server-js NPM package in your project.

npm install @developers.cash/cash-pay-server-js --save

... or alternatively, load it from a CDN:

<script src="https://cdn.jsdelivr.net/npm/@developers.cash/cash-pay-server-js/dist/cashpay.min.js"></script>

Server-side Code for creating and marking as paid:

const CashPay = require('@developers.cash/cash-pay-server-js')

// ...

// Create invoice 
async function requestInvoice(req, res) {
  try {
    // Do things - get list of items in order, calculate totals, etc
    // req.body.items

    // Create the invoice
    let invoice = new CashPay.Invoice()
      .setAPIKey('someRandomString') // Optional (but allows use of Admin Interface)
      .addAddress('bitcoincash:qz8dt7dlwkc5n4x9u6gclfwte8lr7n58gyavxt0vmp', "0.25USD")
    await invoice.create()
    
    // Save invoiceId to database, etc
    // const invoiceId = invoice.id

    // Return payload to client-side (ExpressJS Example)
    return res.send(invoice.payload())
  } catch (err) {
    return res.send(err)
  }
}

// Mark invoice as paid
async function invoicePaid(req, res) {
  try {
    // Verify signature of event (to prevent spoofing)
    await CashPay.Signatures.verifyEvent(req.body.event)
    
    // Do things - mark as paid in database, etc
    if (req.body.event.event === 'broadcasted') {
      // const invoiceId = event.invoice.id
    }
    
    return res.send({ status: 'ok' })
  } catch (err) {
    return res.send(err)
  }
}

Render the created invoice on your client-side

<!-- head -->
<script src="https://cdn.jsdelivr.net/npm/@developers.cash/cash-pay-server-js/dist/cashpay.min.js"></script>
<!-- Or if using NPM, use the browser optimized version -->
<!-- const CashPay = require('@developers.cash/cash-pay-server-js/browser')

<!-- body -->
<div id="invoice-container"></div>

<script>
async function fetchInvoice() {
  // Request invoice from server endpoint
  let invoice = new CashPay.Invoice()
    .intoContainer(document.getElementById('invoice-container'))
    .on(['broadcasted'], e => {
      axios.post('https://api.yoursite.com/invoice-paid', {
        event: e
      })
    })

  // Fetch the invoice that we created on the server-side
  await invoice.createFrom('https://api.yoursite.com/request-invoice', {
    items: ['ITEM_001', 'ITEM-002']
  })
}

fetchInvoice()
</script>

The default template uses inline SVG's and can be styled using CSS:

#invoice-container {
  margin: auto;
  max-width: 150px;
  font-size: 0.8em;
}

.cashpay-loading {
  fill: #00c58a !important;
}

.cashpay-tick {
  fill: #00c58a !important;
}

.cashpay-cross {
  fill: #F00 !important;
}

Webhooks

Webhooks are also available. Using Webhooks instead of the Websocket Events generally provides more resilience over passing Websocket events to the server-side, but are also more difficult to implement as they require a public facing URL.

async function requestInvoice(req, res) {
  // ...
  // It's recommended to include "broadcasting" even if you do not use it explicitly.
  // If your server is down and the "broadcasting" hook fails - the payment will not be broadcasted.
  invoice.setWebhook('https://api.your-site.com/webhook-endpoint', ['broadcasting', 'broadcasted', 'confirmed'])
  // ...
}

async function webhookEndpoint(req, res) {
  try {
    // Verify signature of event (to prevent spoofing) - or check API Key if you don't want to play with signatures
    await CashPay.Signatures.verifyWebhook(req.body, req.headers)
    
    // TODO You'll also want to check the InvoiceID to make sure YOU created this invoice
    
    if (req.body.event === 'broadcasted') {
      // Do things - mark as paid in database, etc
      
      // If a JSON response is given, you can modify "data" and "privateData" on the invoice.
      // 'data' will be available in the corresponding Websocket Event in the browser.
      return res.send({
        data: JSON.stringify({
          redirectURL: 'https://your-site.com/link-to-some-secure-file.mp4'
        })
        privateData: 'SomeOtherData'
      })
    }
    
    if (req.body.event === 'confirmed') {
      // Do things - mark as confirmed in database, etc
    }
    
    res.send({ status: 'OK' })
  } catch (err) {
    return res.send(err)
  }
}

Webhooks that do not give a 200 status code are considered failures.

Using a different CashPayServer Instance

See documentation about Self-Hosting.

const CashPay = require('@developers-cash/cash-pay-server-js')

CashPay.config.options.endpoint = 'https://pay.your-instance.com'

Creating an Invoice Client-Side

Invoices can also be created directly in the browser.

Note that creating the invoice in the browser is insecure for most use-cases.

However, it can be useful for testing.

<!-- head -->
<script src="https://cdn.jsdelivr.net/npm/@developers.cash/cash-pay-server-js/dist/cashpay.min.js"></script>
<!-- Or if using NPM, use the browser optimized version -->
<!-- const CashPay = require('@developers.cash/cash-pay-server-js/browser')

<!-- body -->
<div id="invoice-container"></div>

<script>
// Create the invoice
async function createInvoice() {
  let invoice = new CashPay.Invoice()
    .intoContainer(document.getElementById('invoice-container'))
    .addAddress('bitcoincash:qz8dt7dlwkc5n4x9u6gclfwte8lr7n58gyavxt0vmp', "0.25USD")
  await invoice.create()
}

createInvoice()
</script>

Other common use-cases

// Setting API Key across all new invoices
CashPay.config.invoice.apiKey = 'someRandomString'

// Changing the expiry time on an invoice
invoice.setExpires(60*5) // Five minutes

// Set the memo that the user sees in wallet
invoice.setMemo('Please confirm your order')

//Set Merchant Data (as per BIP70 spec)
invoice.setMerchantData(JSON.stringify({
  someWalletFeature: true
}))

// Set Public Data (will be available in WebSocket events - i.e. not private)
invoice.setData("InvoiceID:1000") // String
invoice.setData({
  redirectURL: '/gated-content/some-page'
})

// Set Private Data (only accessible through Admin and Webhooks)
invoice.setPrivateData("Some String") // String
invoice.setPrivateData({ some: "String"}) // Objects will be cast to a string

// Set user currency (Currency equivalent of BCH will be shown on rendered invoice)
invoice.setUserCurrency('AUD') // Australian Dollars

Issues/Feature Requests

Please submit any issues with the library to the Github Repo's Issues Tracker.

I'm also contactable on Telegram via https://t.me/jimtendo