Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

lnurl

chill1172.7kMIT0.27.0

Node.js implementation of lnurl

lnurl, bitcoin, lightning, lightning network

readme

lnurl-node

Build Status

Node.js implementation of lnurl. The purpose of this project is to provide an easy and flexible lnurl server that you can run as a stand-alone process (via CLI) or integrated with your own custom node.js application (via API).

Optionally, your lnurl server can authorize other applications (offline or otherwise). Possible use-cases include offline Lightning Network ATMs (e.g. Bleskomat), static QR codes for receiving donations, authentication mechanism for web sites or web services (login / registration / 2FA).

This project attempts to maintain backwards compatibility for any features, methods, options, hooks, and events which are documented here.

Specification Support

The LNURL specification is divided into separate documents called "LUDs". These documents can be found in the lnurl-rfc repository.

The following is a list of LUDs which this module already (or plans to) support:

  • <input checked="" disabled="" type="checkbox"> LUD-01 - encode/decode
  • <input checked="" disabled="" type="checkbox"> LUD-02 - channelRequest
  • <input checked="" disabled="" type="checkbox"> LUD-03 - withdrawRequest
  • <input checked="" disabled="" type="checkbox"> LUD-04 - auth
  • <input checked="" disabled="" type="checkbox"> LUD-06 - payRequest
  • <input disabled="" type="checkbox"> LUD-08 - Fast withdrawRequest
  • <input checked="" disabled="" type="checkbox"> LUD-09 - successAction in payRequest
  • <input disabled="" type="checkbox"> LUD-10 - aes successAction in payRequest
  • <input checked="" disabled="" type="checkbox"> LUD-12 - Comments in payRequest
  • <input disabled="" type="checkbox"> LUD-16 - Lightning Address
  • <input disabled="" type="checkbox"> LUD-17 - New URI schema prefixes

Installation

If you wish to use this module as a CLI tool, install it globally via npm:

npm install -g lnurl

Add to your application via npm:

npm install lnurl --save

This will install lnurl and add it to your application's package.json file.

Command-line interface

This section assumes that you have lnurl installed globally and that it is available on your current user's PATH.

CLI: help

To view the help menu:

lnurl --help

CLI: encode

Encode a URL:

lnurl encode "https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df"

Expected output:

lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns

This command also accepts piped input. For example:

echo -n "https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df" \
    | lnurl encode

CLI: decode

Decode an lnurl:

lnurl decode "lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns"

Expected output:

https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df

This command also accepts piped input. For example:

echo -n "lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns" \
    | lnurl decode

CLI: generateNewUrl

To generate a new lnurl that a client application can then use:

lnurl generateNewUrl \
    --host "localhost" \
    --port "3000" \
    --endpoint "/lnurl" \
    --store.backend "knex" \
    --store.config '{"client":"postgres","connection":{"host":"127.0.0.1","user":"postgres","password":"example","database":"lnurl_example"}}' \
    --tag "withdrawRequest" \
    --params '{"minWithdrawable":10000,"maxWithdrawable":10000,"defaultDescription":""}'

See Tags and Parameters for a full list of possible tags and params.

Alternatively, a configuration file can be used:

lnurl generateNewUrl \
    --configFile ./config.json \
    --tag "withdrawRequest" \
    --params '{"minWithdrawable":10000,"maxWithdrawable":10000,"defaultDescription":""}'

Example output:

{
    "encoded": "lnurl1dp68gup69uhkcmmrv9kxsmmnwsarxvpsxqhkcmn4wfkr7ufavvexxvpk893rswpjxcmnvctyvgexzen9xvmkycnxv33rvdtrvy6xzv3ex43xzve5vvexgwfj8yenxvm9xaskzdmpxuexywt9893nqvcly0lgs",
    "secret": "c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03",
    "url": "http://localhost:3000/lnurl?q=c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03"
}

It is possible to set the number of uses allowed for the new URL:

lnurl generateNewUrl \
    --configFile ./config.json \
    --tag "withdrawRequest" \
    --params '{"minWithdrawable":10000,"maxWithdrawable":10000,"defaultDescription":""}' \
    --uses 3

Set --uses equal to 0 to allow the URL to be used an unlimited number of times.

For a list of available options:

lnurl generateNewUrl --help

It is also possible to generate lnurls in other ways:

CLI: server

Start an lnurl application server with the following command:

lnurl server \
    --host "localhost" \
    --port "3000" \
    --lightning.backend "dummy" \
    --lightning.config '{}'
  • The example above uses the "dummy" LN backend. For details about how to connect to a real LN backend, see Supported Lightning Network Backends
  • By default the lnurl server stores data in memory - which is fine for development and testing. But once you plan to run it in production, it is recommended that you use a proper data store - see Configuring Data Store.
  • To enable debugging messages, see the Debugging section of this readme.

Alternatively, a configuration file can be used:

lnurl server --configFile ./config.json

To print all available options for the server command:

lnurl server --help

API

encode

encode(url)

Encode a url as a bech32-encoded string.

Usage:

const lnurl = require('lnurl');
const encoded = lnurl.encode('https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df');
console.log(encoded);

Expected output:

"lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns"

decode

decode(url)

Decode a bech32-encoded lnurl.

Usage:

const lnurl = require('lnurl');
const decoded = lnurl.decode('lnurl1dp68gurn8ghj7um9wfmxjcm99e3k7mf0v9cxj0m385ekvcenxc6r2c35xvukxefcv5mkvv34x5ekzd3ev56nyd3hxqurzepexejxxepnxscrvwfnv9nxzcn9xq6xyefhvgcxxcmyxymnserxfq5fns');
console.log(decoded);

Expected output:

"https://service.com/api?q=3fc3645b439ce8e7f2553a69e5267081d96dcd340693afabe04be7b0ccd178df"

createServer

createServer([options])

Create and initialize an instance of the lnurl server.

Usage:

const lnurl = require('lnurl');
const server = lnurl.createServer({
    host: 'localhost',
    port: 3000,
    auth: {
        apiKeys: [
            {
                id: '46f8cab814de07a8a65f',
                key: 'ee7678f6fa5ab9cf3aa23148ef06553edd858a09639b3687113a5d5cdb5a2a67',
                encoding: 'hex',
            },
        ],
    },
    lightning: {
        backend: 'dummy',
        config: {},
    },
});
  • The example above uses the "dummy" LN backend. For details about how to connect to a real LN backend, see Supported Lightning Network Backends
  • By default the lnurl server stores data in memory - which is fine for development and testing. But once you plan to run it in production, it is recommended that you use a proper data store - see Configuring Data Store.
  • To enable debugging messages, see the Debugging section of this readme.

createServer: options

Below is the full list of options that can be passed to the createServer method.

{
    // The host for the web server:
    host: 'localhost',
    // The port for the web server:
    port: 3000,
    // Whether or not to start listening when the server is created:
    listen: true,
    // Whether or not to allow CORS requests:
    cors: false,
    // The URL where the server is externally reachable (e.g "https://your-lnurl-server.com"):
    url: null,
    // The URI path of the web API end-point:
    endpoint: '/lnurl',
    // See list of possible LN backends here:
    // https://github.com/chill117/lnurl-node#supported-lightning-network-backends
    lightning: {
        // The name of the LN backend to use:
        backend: 'dummy',
        // Configuration options to pass to LN backend:
        config: {},
    },
    store: {
        // Name of store backend ('knex', 'memory'):
        backend: 'memory',
        // Configuration options to pass to store:
        config: {},
    },
    payRequest: {
        // A number greater than 0 indicates the maximum length of comments.
        // Setting this to 0 ignores comments.
        //
        // Note that there is a generally accepted limit (2000 characters)
        // to the length of URLs; see:
        // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers/417184#417184
        //
        // Since comments are sent as a query parameter to the callback URL,
        // this limit should be set to a maximum of 1000 to be safe.
        commentAllowed: 500,
        // Default metadata to be sent in response object:
        metadata: '[["text/plain", "lnurl-node"]]',
    },
}

generateNewUrl

generateNewUrl(tag, params)

To generate a new lnurl that a client application can then use:

const tag = 'payRequest';
const params = {
    minSendable: 10000,
    maxSendable: 200000,
    metadata: '[["text/plain", "lnurl-node"]]',
    commentAllowed: 500,
};
server.generateNewUrl(tag, params).then(result => {
    const { encoded, secret, url } = result;
    console.log({ encoded, secret, url });
}).catch(error => {
    console.error(error);
});

Expected output:

{
    "encoded": "lnurl1dp68gup69uhkcmmrv9kxsmmnwsarxvpsxqhkcmn4wfkr7ufavvexxvpk893rswpjxcmnvctyvgexzen9xvmkycnxv33rvdtrvy6xzv3ex43xzve5vvexgwfj8yenxvm9xaskzdmpxuexywt9893nqvcly0lgs",
    "secret": "c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03",
    "url": "http://localhost:3000/lnurl?q=c2c069b882676adb2afe37bbfdb65ca4a295ba34c2d929333e7aa7a72b9e9c03"
}

See Tags and Parameters for a full list of possible tags and params.

It is possible to set the number of uses allowed for the new URL:

const tag = 'payRequest';
const params = {
    minSendable: 10000,
    maxSendable: 200000,
    metadata: '[["text/plain", "lnurl-node"]]',
    commentAllowed: 500,
};
const options = {
    uses: 3,
};
server.generateNewUrl(tag, params, options).then(result => {
    const { encoded, secret, url } = result;
    console.log({ encoded, secret, url });
}).catch(error => {
    console.error(error);
});

Set uses equal to 0 to allow the URL to be used an unlimited number of times.

It is also possible to generate lnurls in other ways:

Tags and Parameters

Below you will find all tags and their associated params.

channelRequest:

name type notes
localAmt integer (sats) > 0
pushAmt integer (sats) <= localAmt

login:

none

payRequest:

name type notes
minSendable integer (msats) > 0
maxSendable integer (msats) >= minSendable
metadata string stringified JSON
commentAllowed integer character limit for comments (max. 1000), set to 0 to disallow comments

withdrawRequest:

name type notes
minWithdrawable integer (msats) > 0
maxWithdrawable integer (msats) >= minWithdrawable
defaultDescription string

Hooks

It is possible to further customize your lnurl server by using hooks to run custom application code at key points in the server application flow.

How to use a hook:

const lnurl = require('lnurl');
const server = lnurl.createServer();
const { HttpError } = require('lnurl/lib');

// The callback signature can vary depending upon the hook used:
server.bindToHook('HOOK', function(arg1, arg2, arg3, next) {
    // Fail the request by calling next with an error:
    next(new Error('Your custom error message'));
    // Use the HttpError constructor to pass the error to the response object:
    next(new HttpError('Custom error sent in the response object', 400/* status code */));
    // Or call next without any arguments to continue with the request:
    next();
});

Hook: error

This hook is called when any request fails with an error.

Override the existing error with a new error:

server.bindToHook('error', function(error, req, res, next) {
    // Call next with a new error which will be passed to the default error handler:
    next(new HttpError('A new error message', 400));
});

Continue with the existing error:

server.bindToHook('error', function(error, req, res, next) {
    // Call next with no arguments to let the error pass-thru to the default error handler:
    next();
});

Make a custom response:

server.bindToHook('error', function(error, req, res, next) {
    // Use the response object to make a custom response:
    res.status(200).json({ message: 'custom error handling' });
    // Do not call next in this case.
});

Hook: status

This hook is called when a request is received at the web server's /status end-point.

Example OK status response:

server.bindToHook('status', function(req, res, next) {
    // Call next() with no arguments to continue with the normal status flow.
    next();
});

Example failed status response:

server.bindToHook('status', function(req, res, next) {
    // Or, call next with an error to fail the request:
    next(new HttpError('Service temporarily unavailable', 503));
});

Hook: url:process

This hook is called when a request is received at the web server's LNURL end-point.

Example modifying the request object:

server.bindToHook('url:process', function(req, res, next) {
    req.query.defaultDescription = 'custom default description';
    next();// Call next() with no arguments to continue the request.
});

Example rejecting the request:

server.bindToHook('url:process', function(req, res, next) {
    // Call next() with an error to fail the request:
    next(new HttpError('Failed check', 400));
});

Hook: login

login

The lnurl-auth subprotocol allows users to login/authenticate with your service. You can use the login hook as shown here to execute your own custom code whenever there is a successful login/authentication attempt for your server.

server.bindToHook('login', function(key, next) {
    // This code is executed when the lnurl-auth checks have passed (e.g valid signature provided).
    // `key` is the public linking key which has just authenticated.
    // Perform asynchronous code such as database calls here.
    // Call next() without any arguments to continue with the request:
    next();
});

Hook: channelRequest:validate

Hook: payRequest:validate

Hook: withdrawRequest:validate

channelRequest:validate payRequest:validate withdrawRequest:validate

These hooks are called when validating the parameters provided when creating a new URL. For example, when calling server.generateNewUrl(tag, params).

server.bindToHook('channelRequest:validate', function(params, next) {
    // Throw an error to prevent the creation of the new URL:
    next(new Error('Invalid params!'));
    // Call next() without any arguments to continue with the creation of the new URL:
    next();
});

Hook: channelRequest:info

Hook: payRequest:info

Hook: withdrawRequest:info

channelRequest:info payRequest:info withdrawRequest:info

These hooks are called when the initial request is made to the LNURL end-point. The initial request occurs when a wallet app first scans a QR code containing an LNURL. The wallet app makes the initial request for more information about the tag and other parameters associated with the LNURL it just scanned.

server.bindToHook('channelRequest:info', function(secret, params, next) {
    // `secret` is the k1 value that when hashed gives the unique `hash`
    //  associated with an LNURL in the data store.
    // `params` are the parameters provided when the URL was created.
    // Throw an error to fail the request:
    next(new HttpError('Custom error sent in the response object', 400/* status code */));
    // Call next() without any arguments to continue with the request:
    next();
});

Hook: channelRequest:action

Hook: payRequest:action

Hook: withdrawRequest:action

channelRequest:action payRequest:action withdrawRequest:action

These hooks are called when the second request is made to the LNURL end-point. This request occurs when the wallet app wants to complete the action associated with the LNURL it scanned and made an initial request for previously.

  • channelRequest:action - Wallet app sends its node ID and whether or not to make the channel private:
    • remoteid - remote node ID (public key) to which the server should open a channel
    • private - 0 or 1
  • payRequest:action - Wallet sends the amount it wants to pay and an optional comment:
    • amount - amount the server should use when generating a new invoice
  • withdrawRequest:action - Wallet sends a bolt11 invoice that the server should pay:
    • pr - bolt11 invoice
server.bindToHook('channelRequest:action', function(secret, params, next) {
    // `secret` is the k1 value that when hashed gives the unique `hash`
    //  associated with an LNURL in the data store.
    // `params` are the parameters provided when the URL was created plus
    // the parameters provided in the request to the server.
    // Throw an error to fail the request:
    next(new HttpError('Custom error sent in the response object', 400/* status code */));
    // Call next() without any arguments to continue with the request:
    next();
});

Note that these hooks are executed before the server calls the LN backend method. So if an error is thrown here, a channel will not be opened; a new invoice will not be generated; the provided invoice will not be paid.

Events

The server object extends from the event emitter class. It is possible to listen for events as follows:

const lnurl = require('lnurl');
const server = lnurl.createServer();

server.on('EVENT', function(event) {
    // The event object varies depending upon the event type.
});

Event: login

This event is emitted after a successful login attempt.

server.on('login', function(event) {
    const { key, hash } = event;
    // `key` - the public key as provided by the LNURL wallet app
    // `hash` - the hash of the secret for the LNURL used to login
});

Event: channelRequest:action:processed

This event is emitted after a successful call to the LN backend's openChannel method.

server.on('channelRequest:action:processed', function(event) {
    const { secret, params, result } = event;
    // `result` is the non-normalized response object from the LN backend
    // So this will vary depending upon the backend used.
});

Event: payRequest:action:processed

This event is emitted after a successful call to the LN backend's addInvoice method.

server.on('payRequest:action:processed', function(event) {
    const { secret, params, result } = event;
    const { id, invoice } = result;
    // `id` - non-standard reference ID for the new invoice, can be NULL if none provided
    // `invoice` - bolt11 invoice
});

Event: withdrawRequest:action:processed

This event is emitted after a successful call to the LN backend's payInvoice method.

server.on('withdrawRequest:action:processed', function(event) {
    const { secret, params, result } = event;
    const { id } = result;
    // `id` - non-standard reference ID for the payment, can be NULL if none provided
});

Event: channelRequest:action:failed

This event is emitted after a failed call to the LN backend's openChannel method.

server.on('channelRequest:action:failed', function(event) {
    const { secret, params, error } = event;
    // `error` - error from the LN backend
});

Event: payRequest:action:failed

This event is emitted after a failed call to the LN backend's addInvoice method.

server.on('payRequest:action:failed', function(event) {
    const { secret, params, error } = event;
    // `error` - error from the LN backend
});

Event: withdrawRequest:action:failed

This event is emitted after a failed call to the LN backend's payInvoice method.

server.on('withdrawRequest:action:failed', function(event) {
    const { secret, params, error } = event;
    // `error` - error from the LN backend
});

Supported Lightning Network Backends

See lightning-backends for a list of supported Lightning Network backends and their corresponding configuration options.

Configuring Data Store

By default the lnurl server will store data in memory - which is not ideal for several reasons. It is strongly recommended that you configure a proper data store for your server. This module supports PostgreSQL.

PostgreSQL

To use PostgreSQL as your data store you will need to install the postgres module and knex wherever you are running your lnurl server:

npm install knex pg

Then you can run your server via the API as follows:

const lnurl = require('lnurl');
const server = lnurl.createServer({
    // ...
    store: {
        backend: 'knex',
        config: {
            client: 'postgres',
            connection: {
                host: '127.0.0.1',
                user: 'lnurl_server',
                password: '',
                database: 'lnurl_server',
            },
        },
    },
    // ...
});

Or via the CLI:

lnurl server \
    --store.backend="knex" \
    --store.config='{"client":"postgres","connection":{"host":"127.0.0.1","user":"lnurl_server","password":"","database":"lnurl_server"}}'

Debugging

This module uses debug to output debug messages to the console. To output all debug messages, run your node app with the DEBUG environment variable:

DEBUG=lnurl* node your-app.js

Or if using the CLI interface:

DEBUG=lnurl* lnurl server

Tests

To run all tests:

npm test

Changelog

See CHANGELOG.md

License

This software is MIT licensed:

A short, permissive software license. Basically, you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source. There are many variations of this license in use.

changelog

Changelog

  • v0.27.0:
    • New "cors" option that when enabled the server will allow CORS requests - disabled by default.
    • Upgrade dependencies
  • v0.26.2:
    • Latest lightning-backends fixed GetAlby (again)
  • v0.26.1:
    • Latest lightning-backends fixed GetAlby bug w/ latest LndHub credentials
    • Upgrade dependencies
  • v0.26.0:
    • New error hook
    • Upgrade dependencies
  • v0.25.2:
    • Use latest lightning-backends with fixed LNBits backend
  • v0.25.1:
    • Use latest lightning-backends with downgraded dependencies - this fixes incompatibility with older nodejs
  • v0.25.0:
    • Server.generateNewUrl method now accepts a pre-defined "k1" value. If not provided, then the "k1" value is randomly generated - the previous behavior.
    • Upgraded dependencies
  • v0.24.2:
    • Upgraded dependencies
  • v0.24.1:
    • Upgraded lightning-backends
  • v0.24.0:
    • "url:process" hook called before signature check
    • C-Lightning backend now supported via JSON-RPC unix sock or HTTP-RPC API provided by Sparko plugin
  • v0.23.0:
    • Added "status" and "url:process" hooks
  • v0.22.0:
    • Deprecated and will be removed from future v1.0.0 release:
      • SQLite and MySQL as data store backend
      • Built-in support for signed LNURLs
    • Refactoring:
      • Abstract parts of this module to lnurl-offline and lightning-backends modules
      • Use promises instead of async.js where possible
      • Removed underscore dependency
  • v0.21.0:
    • LUD-09 successAction url, message support
  • v0.20.2:
    • Data store (knex): Gracefully wait for a database connection or timeout after 30 seconds (default)
      • Fails immediately with any error other than ECONNREFUSED
  • v0.20.1:
    • Use secp256k1 with elliptic.js instead of using C bindings compiled via node-gyp
      • This improves the portability of this module
    • Upgrade dependencies
  • v0.20.0:
    • New option added to all LN backends ("baseUrl") - specify the full URL where the LN backend HTTP API can be reached.
  • v0.19.1:
    • Fix msats vs. sats usage for addInvoice method of few LN backend APIs
    • Change default hostname of lnbits LN backend to legend.lnbits.com
    • Change default hostname config option of lntxbot LN backend to lntxbot.com
    • Improved error logging with knex data store
  • v0.19.0:
    • General documentation improvements, including information about previously un-documented events and hooks
    • Added url:signed hook which should be used instead of the deprecated middleware:signedLnurl:afterCheckSignature hook.
    • Remove "successAction": null from lnurl-pay response object due to problems with JSON parsing in some languages and libraries.
    • Added support for lnurl-pay comment (LUD-12)
    • New Lightning backends available: coinos, lnbits, lndhub (bluewallet), lnpay, lntxbot, opennode.
    • Fix bug in CLI command lnurl server --configFile ./config.json when missing "lightning" or "store" options in the configuration file. The default options will now correctly be used in this case.
    • Added support for LN backend behind TOR hidden service.
    • Deprecated "protocol" configuration option. Will be removed completely from CLI and API in a future release.
  • v0.18.1:
    • Upgraded dependencies
  • v0.18.0:
    • Dropped support for Eclair and C-Lightning LN backends
    • New HttpLightningBackend class for creating custom HTTP LN backends
  • v0.17.0:
    • Added "useIdentifier", "settled" options to dummy lightning backend
  • v0.16.1:
    • Fix sqlite3 unique index for urls.hash
    • Fix CLI generateNewUrl unknown options error
  • v0.16.0:
    • Upgraded dependencies
    • LN backends:
      • openChannel now returns complete non-normalized result
      • addInvoice now returns { id: NULL or 'STRING', invoice: 'STRING' } on success
      • payInvoice now returns { id: NULL or 'STRING' } on success
      • getInvoiceStatus should be used to check if an invoice was settled
      • dummy: More customization
    • events:
      • withdrawRequest:action:processed now passes thru the result from successful subprotocol action
  • v0.15.0:
    • Removed previously deprecated methods/prototypes from Server prototype: generateApiKey, HttpError. These are available in lnurl/lib.
    • Removed lightning node API mocks
    • The "https" protocol is no longer supported by the server. The server should be run behind a proxy (e.g nginx) that handles TLS termination and request proxying to the HTTP server of lnurl-node.
  • v0.14.0:
    • Added new hooks for inserting validation and other logic at important points in each subprotocol's execution:
      • channelRequest:validate, payRequest:validate, withdrawRequest:validate - After default validations have passed while creating a new URL for for the specified subprotocol.
      • channelRequest:info, payRequest:info, withdrawRequest:info - Before the specified subprotocol's informational JSON response object is sent.
      • channelRequest:action, payRequest:action, withdrawRequest:action - Before the specified subprotocol's LN backend action is executed.
    • Added new events after execution of LN backend actions:
      • channelRequest:action:processed, payRequest:action:processed, withdrawRequest:action:processed - After successful execution.
      • channelRequest:action:failed, payRequest:action:failed, withdrawRequest:action:failed - After failed execution.
    • Fix for SafeEventEmitter: It is now safe to throw an error inside of an event listener callback. Thrown error will be written to the debug stream.
    • Removed previously deprecated methods from Server prototype: deepClone, generateRandomKey, hash, isHex.
    • Deprecated the following methods/prototypes on the Server prototype: generateApiKey, HttpError.
  • v0.13.0:
    • Added GET HTTP /status end-point. Response is HTTP 200 and JSON object { status: 'OK' } when server is up.
  • v0.12.2:
    • Upgraded dependencies
  • v0.12.1:
    • Use unshortened query as payload when verifying signatures. Signatures should be created before shortening.
  • v0.12.0:
    • Standardize query object stringification to ensure consistent signature generation on device and server. Query object should be sorted by key alphabetically then stringified. The resulting "payload" can then be signed.
    • Fixed issue #28 - will no longer mark a URL as used in the case of LN backend request failure.
    • Numbers in querystrings will no longer be automatically shortened w/ e-notation.
  • v0.11.1:
    • prepareSignedQuery which is used by createSignedUrl will now use the value of apiKey.encoding to create a buffer instance from apiKey.key.
  • v0.11.0:
    • generateApiKey now provides "encoding" of the generated API key. This will allow the signature checks to be performed with the key in the correct encoding.
    • Fix for knex (for SQLite3 only) data store: The unique constraint on the hash column (defined in the urls table initialization) was being dropped (or ignored) by knex during each table alteration. A new migration to be run only if using SQLite3 will ensure the unique constraint is redefined after all migrations have run.
  • v0.10.1:
    • CLI:
      • Fix: server command's --endpoint argument now properly passed as option to createServer
      • Fix: generateNewUrl command with --uses 0 now allows unlimited uses as expected
      • Fix: generateNewUrl command no longer causes generation of TLS cert, key files
  • v0.10.0:
    • Added console warning if using memory data store
    • New schema for knex data store - data migration from previous versions is automated:
      • Removed data column - now data is stored as tag, params, apiKeyId columns
      • Added initialUses and remainingUses columns
      • Added timestamp columns (createdAt, updatedAt)
    • Added "uses" allowing for the creation of URLs that can be used a specific number of times (or unlimited)
    • Removed Redis support
  • v0.9.0:
    • New top-level method "createSignedUrl"
    • CLI:
      • Command added ("generateNewUrl"); see Generate a new URL
      • "generateApiKey" will now print result without newline character at end of output
  • v0.8.0:
    • CLI:
      • encode/decode will now print result without newline character at end of output
    • Updated dependencies
  • v0.7.1:
    • Provide "altNames" when creating own self-signed TLS certificates (mock lnd, lnurl-server instance) - this will prevent errors when setting "host" option to a value other than localhost (e.g "127.0.0.1")
    • Set "Cache-Control: private" header for lnurl-pay action requests. This tells HTTP proxies to not cache the response - which is important because the same URL and query string can yield different responses (e.g different payment requests) each time the lnurl-pay URL is called.
    • Fixes for changes to lnd's REST API; specifically opening channels and paying invoices.
  • v0.7.0:
  • v0.6.0:
    • Added new option "mock". When set to TRUE, the server will create its own mock instance of the specified Lightning Node. Useful for quick prototyping and testing.
  • v0.5.2:
    • Mocks and a few utility functions now available in package; see ./mocks/ and ./lib/ respectively
    • Fix for HTTPError constructor prototype
  • v0.5.1:
    • Added "login" event
    • Now providing req object with "request:" events
  • v0.5.0:
    • Added new "login" hook
    • Fixes for login subprotocol
    • Added support for "payRequest" subprotocol
    • Added new events for server instance:
      • "request:received"
      • "request:processing"
      • "request:processed"
      • "request:failed"
    • Updated dependencies
  • v0.4.0:
    • Added support for c-lightning and Eclair as LN backends
    • New protocol server option that allows the use of unencrypted http - the default remains https
  • v0.3.1:
    • Use Number type for min/maxWithdrawable (lnurl-withdraw)
  • v0.3.0:
    • generateApiKey() (both API and CLI) has new options for setting the encoding (hex or base64) and number of random bytes
    • CLI: Can now pipe to encode/decode
    • Fix for withdrawRequest: Now using MilliSatoshis for amounts rather than Satoshis.
  • v0.2.0:
    • Added hooks for custom application code including custom middleware. See Hooks for more information.
    • Now supports API key authorization via HMAC. This allows other (even offline!) applications to create authorized lnurls for your lnurl server. See Signed LNURLs for more information.
    • Removed POST /lnurl HTTPS end-point and related excludeWriteEndpoint option
    • Removed apiKeyHash option and replaced with auth.apiKeys option; see Signed LNURLs for more information.
    • generateApiKey() no longer includes hash but now returns id instead (e.g {"id":"HEX","key":"HEX"}).
    • lnurl generateApiKey now returns stringified JSON so that it is possible to pipe the output directly to utilities such as jq
    • Provide server configuration via file to CLI
    • Datastores: memory, redis, knex (sqlite/mysql/postgres)