Security News
Research
Supply Chain Attack on Rspack npm Packages Injects Cryptojacking Malware
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
alby-js-sdk
Advanced tools
This JavaScript SDK for the Alby OAuth2 Wallet API and the Nostr Wallet Connect API.
npm install alby-js-sdk
This library relies on a global fetch() function which will work in browsers and node v18.x or newer. (In older versions you have to use a polyfill.)
Nostr Wallet Connect is an open protocol enabling applications to interact with bitcoin lightning wallets. It allows users to connect their existing wallets to your application allowing developers to easily integrate bitcoin lightning functionality.
The Alby JS SDK allows you to easily integrate Nostr Wallet Connect into any JavaScript based application.
The NostrWebLNProvider
exposes the WebLN sendPayment interface to execute lightning payments through Nostr Wallet Connect.
(note: in the future more WebLN functions will be added to Nostr Wallet Connect)
providerName
: name of the provider to load the default options. currently alby
(default)nostrWalletConnectUrl
: full Nostr Wallet Connect URL as defined by the specrelayUrl
: URL of the Nostr relay to be used (e.g. wss://nostr-relay.getalby.com)walletPubkey
: pubkey of the Nostr Wallet Connect appsecret
: secret key to sign the request event (if not available window.nostr will be used)authorizationUrl
: URL to the NWC interface for the user to and the app connectionimport { webln } from "alby-js-sdk";
const nwc = new webln.NostrWebLNProvider({ nostrWalletConnectUrl: loadNWCUrl() }); // loadNWCUrl is some function to get the NWC URL from some (encrypted) storage
// or use the short version
const nwc = new webln.NWC({ nostrWalletConnectUrl: loadNWCUrl });
// connect to the relay
await nwc.enable();
// now you can send payments by passing in the invoice
const response = await nwc.sendPayment(invoice);
You can use NWC as a webln compatible object in your web app:
// you can set the window.webln object to use the universal API to send payments:
if (!window.webln) {
// prompt the user to connect to NWC
window.webln = new webln.NostrWebLNProvider({ nostrWalletConnectUrl: loadNWCUrl })
// now use any webln code
}
The goal of the Nostr Wallet Connect provider is to be API compatible with webln. Currently not all methods are supported and only sendPayment
is specified.
static withNewSecret()
Initialized a new NostrWebLNProvider
instance but generates a new random secret. The pubkey of that secret then needs to be authorized by the user (this can be initiated by redirecting the user to the getAuthorizationUrl()
URL or calling initNWC()
to open an authorization popup.
const nwc = NostrWebLNProvider.withNewSecret();
await nwc.initNWC();
Takes a bolt11 invoice and calls the NWC pay_invoice
function.
It returns a promise object that is resolved with an object with the preimage or is rejected with an error
const nwc = new NostrWebLNProvider({ nostrWalletConnectUrl: loadNWCUrl });
await nwc.enable();
const response = await nwc.sendPayment(invoice);
console.log(response);
Returns the nostr+walletconnect://
URL which includes all the connection information (walletPubkey
, relayUrl
, secret
)
This can be used to get and persist the string for later use.
Opens a new window prompt with the getAuthorizationUrl()
(the user's NWC UI) to ask the user to authorize the app connection.
The promise resolves when the connection is authorized and the popup sends a nwc:success
message or rejects when the prompt is closed.
Pass a name
to the NWC provider describing the application.
const nwc = NostrWebLNProvider.withNewSecret();
try {
await nwc.initNWC({name: 'ACME app' );
} catch(e) {
console.warn("Prompt closed");
}
await nwc.enable();
let response;
try {
response = await nwc.sendPayment(invoice);
// if success then the response.preimage will be only
console.info(`payment successful, the preimage is ${response.preimage}`);
}
catch (e) {
console.error(e.error || e);
}
To use this on Node.js you first must install websocket-polyfill
and import it:
import 'websocket-polyfill';
// or: require('websocket-polyfill');
if you get an crypto is not defined
error you have to import it first:
import * as crypto from 'node:crypto';
global.crypto = crypto;
//or: global.crypto = require('crypto');
import { NostrWebLNProvider } from 'alby-js-sdk';
const webln = new NostrWebLNProvider(); // use defaults (connects to Alby's relay, will use window.nostr to sign the request)
await webln.enable(); // connect to the relay
const response = await webln.sendPayment(invoice);
console.log(response.preimage);
webln.close(); // close the websocket connection
import { NostrWebLNProvider } from 'alby-js-sdk';
const webln = new NostrWebLNProvider({ nostrWalletConnectUrl: 'nostrwalletconnect://69effe7b49a6dd5cf525bd0905917a5005ffe480b58eeb8e861418cf3ae760d9?relay=wss://nostr.bitcoiner.social&secret=c60320b3ecb6c15557510d1518ef41194e9f9337c82621ddef3f979f668bfebd'); // use defaults
await webln.enable(); // connect to the relay
const response = await webln.sendPayment(invoice);
console.log(response.preimage);
webln.close(); // close the websocket connection
// same options can be provided to .withNewSecret() as creating a new NostrWebLNProvider()
const webln = webln.NostrWebLNProvider.withNewSecret();
// get the connect URL to the interface where the user has to enable the connection
webln.getConnectUrl({ name: `My app name` });
// an optional return_to parameter can be passed in
webln.getConnectUrl({ name: `My app name`, returnTo: document.location.toString() });
// or use the `initNWC` helper which opens a popup to initiate the connection flow.
// the promise resolves once the NWC app returned.
await webln.initNWC("alby", {
name: `My app name`,
});
// ... enable and send a payment
// if you want to get the connect url with the secret:
// const nostrWalletConnectUrl nwc.getNostrWalletConnectUrl(true)
Please have a look a the Alby OAuth2 Wallet API:
https://guides.getalby.com/alby-wallet-api/reference/getting-started
const authClient = new auth.OAuth2User({
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
callback: "http://localhost:8080/callback",
scopes: ["invoices:read", "account:read", "balance:read", "invoices:create", "invoices:read", "payments:send"],
token: {access_token: undefined, refresh_token: undefined, expires_at: undefined} // initialize with existing token
});
const authUrl = authClient.generateAuthURL({
code_challenge_method: "S256",
});
// open auth URL
// `code` is passed as a query parameter when the user is redirected back aufter authorization
await authClient.requestAccessToken(code);
// access the token response. You can store this securely for future client initializations
console.log(authClient.token);
// initialize a client
const client = new Client(authClient);
const result = await client.accountBalance();
const token = loadTokenForUser(); // {access_token: string, refresh_token: string, expires_at: number}
const authClient = new auth.OAuth2User({
client_id: process.env.CLIENT_ID,
callback: "http://localhost:8080/callback",
scopes: ["invoices:read", "account:read", "balance:read", "invoices:create", "invoices:read", "payments:send"],
token: token
});
const client = new Client(authClient);
// the authClient will automatically refresh the access token if expired using the refresh token
const result = await client.createInvoice({amount: 1000});
const token = loadTokenForUser(); // {access_token: string, refresh_token: string, expires_at: number}
const authClient = new auth.OAuth2User({
client_id: process.env.CLIENT_ID,
callback: "http://localhost:8080/callback",
scopes: ["invoices:read", "account:read", "balance:read", "invoices:create", "invoices:read", "payments:send"],
token: token
});
const client = new Client(authClient);
// the authClient will automatically refresh the access token if expired using the refresh token
await client.sendPayment({ invoice: bolt11 });
await client.keysend({
destination: nodekey,
amount: 10,
memo: memo
});
refer also to the boostagram spec: https://github.com/lightning/blips/blob/master/blip-0010.md
const token = loadTokenForUser(); // {access_token: string, refresh_token: string, expires_at: number}
const authClient = new auth.OAuth2User({
client_id: process.env.CLIENT_ID,
callback: "http://localhost:8080/callback",
scopes: ["payments:send"],
token: token
});
const client = new Client(authClient);
// the authClient will automatically refresh the access token if expired using the refresh token
// pass in an array if you want to send multiple boostagrams with one call
await client.sendBoostagram({
recipient: {
address: '030a58b8653d32b99200a2334cfe913e51dc7d155aa0116c176657a4f1722677a3',
customKey: '696969',
customValue: 'bNVHj0WZ0aLPPAesnn9M'
},
amount: 10,
// spec: https://github.com/lightning/blips/blob/master/blip-0010.md
boostagram: {
"app_name": "Alby SDK Demo",
"value_msat_total": 49960, // TOTAL Number of millisats for the payment (all splits together, before fees. The actual number someone entered in their player, for numerology purposes.)
"value_msat": 2121, // Number of millisats for this split payment
"url": "https://feeds.buzzsprout.com/xxx.rss",
"podcast": "Podcast title",
"action": "boost",
"episode": "The episode title",
"episode_guid": "Buzzsprout-xxx",
"ts": 574,
"name": "Podcaster - the recipient name",
"sender_name": "Satoshi - the sender/listener name"
}
});
// or manually through the keysend:
// pass in an array if you want to do multiple keysend payments with one call
await client.keysend({
destination: nodekey,
amount: 10,
customRecords: {
"7629169": JSON.stringify(boostagram),
"696969": "user",
}
});
You often want to send a boostagram for multiple splits. You can do this with one API call. Simply pass in an array of boostagrams. See example above.
const response = await client.sendBoostagram([boostagram1, boostagram2, boostagram3]);
console.log(response.keysends);
response.keysends
is an array of objects that either has an error
key if a payment faild or the keysend
key if everything succeeded.
{
"keysends":[
{
"keysend": { "amount":10, "fee":0, "destination":"xx","payment_preimage":"xx","payment_hash":"xx"}
},
{
"keysend":{"amount":10,"fee":0,"destination":"xxx","payment_preimage":"xxx","payment_hash":"xxx"}
}
]
}
This library relies on a global fetch()
function which will only work in browsers and node v18.x or newer. In older versions you can manually install a global fetch option or polyfill if needed.
For example:
import fetch from "cross-fetch"; // or "@inrupt/universal-fetch"
globalThis.fetch = fetch;
// or as a polyfill:
import 'cross-fetch/polyfill';
You can find examples in the examples/ directory.
We are happy to help, please contact us or create an issue.
The client and the setup is inspired and based on the twitter-api-typescript-sdk.
MIT
FAQs
(deprecated use: @getalby/sdk )
The npm package alby-js-sdk receives a total of 53 weekly downloads. As such, alby-js-sdk popularity was classified as not popular.
We found that alby-js-sdk demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.
Security News
Sonar’s acquisition of Tidelift highlights a growing industry shift toward sustainable open source funding, addressing maintainer burnout and critical software dependencies.