├── .gitignore
├── demos
├── html
│ ├── .yarnrc.yml
│ ├── .gitignore
│ ├── package.json
│ ├── bc-button.html
│ ├── README.md
│ └── bc-pay-button.html
├── react
│ ├── src
│ │ ├── vite-env.d.ts
│ │ ├── webln-types.d.ts
│ │ ├── main.tsx
│ │ ├── pages
│ │ │ ├── ConnectDemo.tsx
│ │ │ ├── Home.tsx
│ │ │ ├── BasicButtonDemo.tsx
│ │ │ ├── PaymentButtonDemo.tsx
│ │ │ └── PaymentDemo.tsx
│ │ └── App.tsx
│ ├── README.md
│ ├── tsconfig.node.json
│ ├── vite.config.ts
│ ├── index.html
│ ├── .gitignore
│ ├── .eslintrc.cjs
│ ├── tsconfig.json
│ └── package.json
├── nextjs
│ ├── .eslintrc.json
│ ├── app
│ │ ├── favicon.ico
│ │ ├── layout.tsx
│ │ ├── globals.css
│ │ └── components
│ │ │ └── BitcoinConnectClientWrapper.tsx
│ ├── next.config.js
│ ├── postcss.config.js
│ ├── .gitignore
│ ├── tailwind.config.ts
│ ├── public
│ │ ├── vercel.svg
│ │ └── next.svg
│ ├── tsconfig.json
│ ├── package.json
│ └── README.md
├── nextjs-legacy
│ ├── .eslintrc.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── vercel.svg
│ │ └── next.svg
│ ├── postcss.config.js
│ ├── next.config.js
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ └── api
│ │ │ └── hello.ts
│ ├── .gitignore
│ ├── tailwind.config.ts
│ ├── tsconfig.json
│ ├── styles
│ │ └── globals.css
│ ├── components
│ │ └── BitcoinConnectClientWrapper.tsx
│ ├── package.json
│ └── README.md
└── README.md
├── .eslintignore
├── dev
├── README.md
└── vite
│ ├── src
│ └── vite-env.d.ts
│ ├── README.md
│ ├── .gitignore
│ ├── package.json
│ ├── tsconfig.json
│ ├── button.html
│ ├── connector-list.html
│ ├── pay-button.html
│ ├── button-deeplink.html
│ └── button-nwa.html
├── src
├── webln-types.d.ts
├── types
│ ├── ConnectorFilter.ts
│ ├── PaymentMethods.ts
│ ├── ConnectorType.ts
│ ├── WebLNProviderConfig.ts
│ ├── ConnectorConfig.ts
│ └── BitcoinConnectConfig.ts
├── components
│ ├── icons
│ │ ├── checkIcon.ts
│ │ ├── connectors
│ │ │ ├── lnbitsIcon.ts
│ │ │ ├── albyCloudIcon.ts
│ │ │ ├── lncIcon.ts
│ │ │ ├── lnfiIcon.ts
│ │ │ ├── flashWalleticon.ts
│ │ │ ├── albyGoIcon.ts
│ │ │ ├── coinosIcon.ts
│ │ │ ├── nwcThickIcon.ts
│ │ │ ├── primalIcon.ts
│ │ │ ├── nwcIcon.ts
│ │ │ ├── albyHubIcon.ts
│ │ │ └── cashuMeIcon.ts
│ │ ├── bcConnectedIcon.ts
│ │ ├── crossIcon.ts
│ │ ├── backIcon.ts
│ │ ├── disconnectIcon.ts
│ │ ├── satIcon.ts
│ │ ├── walletIcon.ts
│ │ ├── linkIcon.ts
│ │ ├── copyIcon.ts
│ │ ├── copiedIcon.ts
│ │ ├── helpIcon.ts
│ │ ├── qrIcon.ts
│ │ ├── bcIcon.ts
│ │ ├── bcCircleIcon.ts
│ │ └── waitingIcon.ts
│ ├── connectors
│ │ ├── index.ts
│ │ ├── bc-extension-connector.ts
│ │ ├── bc-generic-nwc-connector.ts
│ │ ├── bc-lnbits-connector.ts
│ │ ├── bc-lnfi-nwc-connector.ts
│ │ ├── bc-rizful-connector.ts
│ │ ├── bc-primal-connector.ts
│ │ ├── bc-flash-connector.ts
│ │ ├── bc-alby-hub-connector.ts
│ │ ├── bc-cashu-me-connector.ts
│ │ ├── bc-lnbits-nwc-connector.ts
│ │ ├── bc-lnc-connector.ts
│ │ ├── bc-coinos-connector.ts
│ │ └── ConnectorElement.ts
│ ├── templates
│ │ ├── hr.ts
│ │ ├── innerBorder.ts
│ │ └── disconnectSection.ts
│ ├── bc-router-outlet.ts
│ ├── internal
│ │ ├── bci-connecting.ts
│ │ ├── bci-button.ts
│ │ └── InternalElement.ts
│ ├── bc-modal.ts
│ ├── bc-navbar.ts
│ ├── pages
│ │ ├── bc-connected.ts
│ │ ├── bc-nwc.ts
│ │ ├── bc-lnfi.ts
│ │ ├── bc-new-wallet.ts
│ │ ├── bc-help.ts
│ │ ├── bc-lnbits-nwc.ts
│ │ ├── bc-alby-hub.ts
│ │ ├── bc-rizful.ts
│ │ ├── bc-cashu-me.ts
│ │ ├── bc-primal.ts
│ │ └── bc-lnbits.ts
│ ├── css
│ │ └── classes.ts
│ ├── images
│ │ └── success.ts
│ ├── routes.ts
│ ├── flows
│ │ ├── bc-connect.ts
│ │ └── bc-payment.ts
│ ├── bc-modal-header.ts
│ ├── BitcoinConnectElement.ts
│ ├── bc-button.ts
│ ├── bc-pay-button.ts
│ ├── bc-start.ts
│ ├── twind
│ │ └── withTwind.ts
│ └── bc-balance.ts
├── connectors
│ ├── Connector.ts
│ ├── ExtensionConnector.ts
│ ├── NWCConnector.ts
│ └── index.ts
├── utils
│ └── base64ToHex.ts
├── index.ts
├── state
│ └── boot.ts
└── test
│ └── my-element_test.ts
├── .prettierrc.json
├── tailwind.config.js
├── react
├── src
│ ├── types
│ │ └── ComponentProps.ts
│ ├── components
│ │ ├── Button.tsx
│ │ ├── Connect.tsx
│ │ ├── Payment.tsx
│ │ └── PayButton.tsx
│ ├── index.ts
│ └── hooks
│ │ ├── useOnPaid.ts
│ │ └── useCoreEvents.ts
├── README.md
├── tsconfig.json
└── package.json
├── .vscode
├── settings.json
└── extensions.json
├── CONTRIBUTING.md
├── tsconfig.json
├── .github
└── workflows
│ └── publish.yml
├── LICENSE
├── .eslintrc.json
├── doc
└── MIGRATION_v3.md
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/demos/html/.yarnrc.yml:
--------------------------------------------------------------------------------
1 | nodeLinker: node-modules
2 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | web-dev-server.config.js
3 |
--------------------------------------------------------------------------------
/demos/html/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .yarn/install-state.gz
--------------------------------------------------------------------------------
/dev/README.md:
--------------------------------------------------------------------------------
1 | # Dev Projects
2 |
3 | - [vite](vite/README.md)
4 |
--------------------------------------------------------------------------------
/dev/vite/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/webln-types.d.ts:
--------------------------------------------------------------------------------
1 | ///
--------------------------------------------------------------------------------
/demos/react/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/types/ConnectorFilter.ts:
--------------------------------------------------------------------------------
1 | export type ConnectorFilter = 'nwc';
2 |
--------------------------------------------------------------------------------
/demos/nextjs/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/demos/react/src/webln-types.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/src/types/PaymentMethods.ts:
--------------------------------------------------------------------------------
1 | export type PaymentMethods = 'all' | 'internal' | 'external';
2 |
--------------------------------------------------------------------------------
/demos/nextjs/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getAlby/bitcoin-connect/HEAD/demos/nextjs/app/favicon.ico
--------------------------------------------------------------------------------
/demos/nextjs-legacy/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/getAlby/bitcoin-connect/HEAD/demos/nextjs-legacy/public/favicon.ico
--------------------------------------------------------------------------------
/demos/nextjs/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {}
3 |
4 | module.exports = nextConfig
5 |
--------------------------------------------------------------------------------
/demos/nextjs/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/src/types/ConnectorType.ts:
--------------------------------------------------------------------------------
1 | import {connectors} from '../connectors';
2 |
3 | export type ConnectorType = keyof typeof connectors;
4 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "singleQuote": true,
5 | "bracketSpacing": false,
6 | "arrowParens": "always"
7 | }
8 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /* empty file required by tailwind css intellisense plugin */
2 | /* we actually use twind but the intellisense does not seem to work there */
3 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | }
5 |
6 | module.exports = nextConfig
7 |
--------------------------------------------------------------------------------
/demos/README.md:
--------------------------------------------------------------------------------
1 | # Demos
2 |
3 | Please note: these demos point at the production version of Bitcoin Connect.
4 |
5 | - [React](react/README.md)
6 | - [Pure HTML](html/README.md)
7 |
--------------------------------------------------------------------------------
/demos/react/README.md:
--------------------------------------------------------------------------------
1 | # demos/react
2 |
3 | A simple example of how to add Bitcoin Connect to your react app
4 |
5 | ## Install
6 |
7 | Run `yarn install`
8 |
9 | ## Development
10 |
11 | Run `yarn dev`
12 |
--------------------------------------------------------------------------------
/src/types/WebLNProviderConfig.ts:
--------------------------------------------------------------------------------
1 | import {NWCAuthorizationUrlOptions} from '@getalby/sdk';
2 |
3 | export type WebLNProviderConfig = {
4 | nwc?: {
5 | authorizationUrlOptions: NWCAuthorizationUrlOptions;
6 | };
7 | };
8 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '@/styles/globals.css'
2 | import type { AppProps } from 'next/app'
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/dev/vite/README.md:
--------------------------------------------------------------------------------
1 | # dev/vite
2 |
3 | Develop Bitcoin Connect components using [Vite](https://vitejs.dev/)
4 |
5 | ## Install
6 |
7 | Run `yarn install` here and in the root directory.
8 |
9 | ## Development
10 |
11 | Run `yarn dev` (either here or in the root directory)
12 |
--------------------------------------------------------------------------------
/src/types/ConnectorConfig.ts:
--------------------------------------------------------------------------------
1 | import {ConnectorType} from './ConnectorType';
2 |
3 | export type ConnectorConfig = {
4 | connectorName: string;
5 | connectorType: ConnectorType;
6 | nwcUrl?: string;
7 | lnbitsInstanceUrl?: string;
8 | lnbitsAdminKey?: string;
9 | };
10 |
--------------------------------------------------------------------------------
/demos/react/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import App from './App.tsx';
4 |
5 | ReactDOM.createRoot(document.getElementById('root') as Element).render(
6 |
7 |
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/demos/react/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "skipLibCheck": true,
5 | "module": "ESNext",
6 | "moduleResolution": "bundler",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/demos/react/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | server: {
8 | port: 3000,
9 | },
10 | base: '/',
11 | })
12 |
--------------------------------------------------------------------------------
/react/src/types/ComponentProps.ts:
--------------------------------------------------------------------------------
1 | import {WebLNProvider} from '@webbtc/webln-types';
2 |
3 | export type ComponentProps = {
4 | onConnected?(provider: WebLNProvider): void;
5 | onConnecting?(): void;
6 | onDisconnected?(): void;
7 | onModalOpened?(): void;
8 | onModalClosed?(): void;
9 | };
10 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from 'next/document'
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/react/README.md:
--------------------------------------------------------------------------------
1 | # Bitcoin Connect React
2 |
3 | A React wrapper for Bitcoin Connect
4 |
5 | ## Development
6 |
7 | `yarn install`
8 | `yarn dev`
9 |
10 | ### Viewing changes
11 |
12 | Run `yarn link` then in `../demos/react` run `yarn link @getalby/bitcoin-connect-react`. The component changes can be seen in the demo app
13 |
--------------------------------------------------------------------------------
/src/components/icons/checkIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | export const checkIcon = svg`
4 |
5 |
6 |
7 | `;
8 |
--------------------------------------------------------------------------------
/src/components/icons/connectors/lnbitsIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | export const lnbitsIcon = svg`
4 |
5 |
6 | `;
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | "dist": true,
4 | "react/dist": true
5 | },
6 | "editor.formatOnSave": true,
7 | "tailwindCSS.experimental.configFile": {
8 | "tailwind.config.js": "src/**",
9 | "website/tailwind.config.js": "website/**"
10 | },
11 | "editor.defaultFormatter": "esbenp.prettier-vscode"
12 | }
13 |
--------------------------------------------------------------------------------
/demos/react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Bitcoin Connect React
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/dev/vite/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/demos/react/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/demos/html/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "bc-button": "wds -r ../.. -o ./demos/html/bc-button.html --watch",
5 | "bc-api-usage": "wds -r ../.. -o ./demos/html/bc-api-usage.html --watch",
6 | "bc-pay-button": "wds -r ../.. -o ./demos/html/bc-pay-button.html --watch"
7 | },
8 | "devDependencies": {
9 | "@web/dev-server": "^0.1.31"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | type Data = {
5 | name: string
6 | }
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) {
12 | res.status(200).json({ name: 'John Doe' })
13 | }
14 |
--------------------------------------------------------------------------------
/src/connectors/Connector.ts:
--------------------------------------------------------------------------------
1 | import {WebLNProvider} from '@webbtc/webln-types';
2 | import {ConnectorConfig} from '../types/ConnectorConfig';
3 |
4 | export abstract class Connector {
5 | protected _config: ConnectorConfig;
6 |
7 | constructor(config: ConnectorConfig) {
8 | this._config = config;
9 | }
10 |
11 | abstract init(): Promise;
12 |
13 | async unload() {}
14 | }
15 |
--------------------------------------------------------------------------------
/dev/vite/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite serve ../.. --open dev/vite/index.html",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "lit": "^3.0.0"
13 | },
14 | "devDependencies": {
15 | "typescript": "^5.0.2",
16 | "vite": "^4.4.5"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/react/src/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import '@getalby/bitcoin-connect';
3 | import {ComponentProps} from '../types/ComponentProps';
4 | import {useCoreEvents} from '../hooks/useCoreEvents';
5 |
6 | type ButtonProps = ComponentProps & {};
7 |
8 | export const Button: React.FC = (props) => {
9 | useCoreEvents(props);
10 |
11 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
12 | // @ts-ignore
13 | return ;
14 | };
15 |
--------------------------------------------------------------------------------
/src/components/icons/bcConnectedIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 |
6 | export const bcConnectedIcon = svg`
7 |
8 |
9 | `;
10 |
--------------------------------------------------------------------------------
/src/utils/base64ToHex.ts:
--------------------------------------------------------------------------------
1 | // from https://github.com/getAlby/lightning-browser-extension/blob/master/src/common/lib/utils.ts#L12
2 | export const base64ToHex = (str: string) => {
3 | const hex = [];
4 | for (
5 | let i = 0, bin = atob(str.replace(/[ \r\n]+$/, ''));
6 | i < bin.length;
7 | ++i
8 | ) {
9 | let tmp = bin.charCodeAt(i).toString(16);
10 | if (tmp.length === 1) tmp = '0' + tmp;
11 | hex[hex.length] = tmp;
12 | }
13 | return hex.join('');
14 | };
15 |
--------------------------------------------------------------------------------
/react/src/components/Connect.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import '@getalby/bitcoin-connect';
3 | import {ComponentProps} from '../types/ComponentProps';
4 | import {useCoreEvents} from '../hooks/useCoreEvents';
5 |
6 | type ConnectProps = ComponentProps & {};
7 |
8 | export const Connect: React.FC = (props) => {
9 | useCoreEvents(props);
10 |
11 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
12 | // @ts-ignore
13 | return ;
14 | };
15 |
--------------------------------------------------------------------------------
/src/components/icons/crossIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 | export const crossIcon = svg`
6 |
7 | `;
8 |
--------------------------------------------------------------------------------
/src/components/connectors/index.ts:
--------------------------------------------------------------------------------
1 | export * from './bc-extension-connector';
2 | export * from './bc-alby-hub-connector';
3 | export * from './bc-generic-nwc-connector';
4 | export * from './bc-lnc-connector';
5 | export * from './bc-lnbits-connector';
6 | export * from './bc-lnbits-nwc-connector';
7 | export * from './bc-lnfi-nwc-connector';
8 | export * from './bc-coinos-connector';
9 | export * from './bc-flash-connector';
10 | export * from './bc-primal-connector';
11 | export * from './bc-rizful-connector';
12 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 |
5 | // List of extensions which should be recommended for users of this workspace.
6 | "recommendations": ["runem.lit-plugin", "esbenp.prettier-vscode"],
7 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
8 | "unwantedRecommendations": []
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/icons/connectors/albyCloudIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | export const albyCloudIcon = svg`
4 |
5 | `;
6 |
--------------------------------------------------------------------------------
/demos/react/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | ignorePatterns: ['dist', '.eslintrc.cjs'],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': [
14 | 'warn',
15 | { allowConstantExport: true },
16 | ],
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/src/connectors/ExtensionConnector.ts:
--------------------------------------------------------------------------------
1 | import {Connector} from './Connector';
2 | import {ConnectorConfig} from '../types/ConnectorConfig';
3 | import {WebLNProvider} from '@webbtc/webln-types';
4 |
5 | export class ExtensionConnector extends Connector {
6 | constructor(config: ConnectorConfig) {
7 | super(config);
8 | }
9 |
10 | init(): Promise {
11 | if (!window.webln) {
12 | throw new Error('No WebLN provider available');
13 | }
14 | return Promise.resolve(window.webln);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/icons/backIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 | // - re-add class="..."
6 |
7 | export const backIcon = svg`
8 |
9 |
10 | `;
11 |
--------------------------------------------------------------------------------
/demos/nextjs/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/demos/nextjs/app/layout.tsx:
--------------------------------------------------------------------------------
1 | import type { Metadata } from 'next'
2 | import { Inter } from 'next/font/google'
3 | import './globals.css'
4 |
5 | const inter = Inter({ subsets: ['latin'] })
6 |
7 | export const metadata: Metadata = {
8 | title: 'Create Next App',
9 | description: 'Generated by create next app',
10 | }
11 |
12 | export default function RootLayout({
13 | children,
14 | }: {
15 | children: React.ReactNode
16 | }) {
17 | return (
18 |
19 | {children}
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/react/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from './components/Button';
2 | export * from './components/PayButton';
3 | export * from './components/Connect';
4 | export * from './components/Payment';
5 | export {
6 | init,
7 | closeModal,
8 | connect,
9 | connectNWC,
10 | disconnect,
11 | isConnected,
12 | launchModal,
13 | launchPaymentModal,
14 | requestProvider,
15 | onConnected,
16 | onConnecting,
17 | onDisconnected,
18 | onModalOpened,
19 | onModalClosed,
20 | getConnectorConfig,
21 | WebLNProviders,
22 | PaymentMethods,
23 | } from '@getalby/bitcoin-connect';
24 |
--------------------------------------------------------------------------------
/demos/nextjs/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss'
2 |
3 | const config: Config = {
4 | content: [
5 | './pages/**/*.{js,ts,jsx,tsx,mdx}',
6 | './components/**/*.{js,ts,jsx,tsx,mdx}',
7 | './app/**/*.{js,ts,jsx,tsx,mdx}',
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
13 | 'gradient-conic':
14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
15 | },
16 | },
17 | },
18 | plugins: [],
19 | }
20 | export default config
21 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/tailwind.config.ts:
--------------------------------------------------------------------------------
1 | import type { Config } from 'tailwindcss'
2 |
3 | const config: Config = {
4 | content: [
5 | './pages/**/*.{js,ts,jsx,tsx,mdx}',
6 | './components/**/*.{js,ts,jsx,tsx,mdx}',
7 | './app/**/*.{js,ts,jsx,tsx,mdx}',
8 | ],
9 | theme: {
10 | extend: {
11 | backgroundImage: {
12 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
13 | 'gradient-conic':
14 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
15 | },
16 | },
17 | },
18 | plugins: [],
19 | }
20 | export default config
21 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "jsx": "preserve",
15 | "incremental": true,
16 | "paths": {
17 | "@/*": ["./*"]
18 | }
19 | },
20 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
21 | "exclude": ["node_modules"]
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/templates/hr.ts:
--------------------------------------------------------------------------------
1 | import {html} from 'lit';
2 | import {classes} from '../css/classes';
3 |
4 | export function hr(text?: string) {
5 | const hrClasses = `border-t ${classes['border-neutral-tertiary']} ${
6 | text ? 'w-24' : 'w-full'
7 | }`;
8 |
9 | return html`
12 |
13 | ${text
14 | ? html`
15 | ${text}
16 |
17 | `
18 | : null}
19 | `;
20 | }
21 |
--------------------------------------------------------------------------------
/demos/nextjs/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/connectors/NWCConnector.ts:
--------------------------------------------------------------------------------
1 | import {Connector} from './Connector';
2 | import {ConnectorConfig} from '../types/ConnectorConfig';
3 | import {WebLNProvider} from '@webbtc/webln-types';
4 | import {NostrWebLNProvider} from '@getalby/sdk';
5 |
6 | export class NWCConnector extends Connector {
7 | constructor(config: ConnectorConfig) {
8 | super(config);
9 | }
10 |
11 | async init(): Promise {
12 | if (!this._config.nwcUrl) {
13 | throw new Error('no nwc URL provided');
14 | }
15 | return new NostrWebLNProvider({
16 | nostrWalletConnectUrl: this._config.nwcUrl,
17 | });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-extension-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {extensionIcon} from '../icons/connectors/extensionIcon';
3 | import {ConnectorElement} from './ConnectorElement';
4 |
5 | @customElement('bc-extension-connector')
6 | export class ExtensionConnector extends ConnectorElement {
7 | constructor() {
8 | super('extension.generic', 'Browser Extensions', '#F4F4F4', extensionIcon);
9 | }
10 |
11 | protected _onClick() {
12 | this._connect({});
13 | }
14 | }
15 |
16 | declare global {
17 | interface HTMLElementTagNameMap {
18 | 'bc-extension-connector': ExtensionConnector;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/components/icons/connectors/lncIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | export const lncIcon = svg` `;
4 |
--------------------------------------------------------------------------------
/demos/nextjs/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
--------------------------------------------------------------------------------
/dev/vite/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "experimentalDecorators": true,
5 | "useDefineForClassFields": false,
6 | "module": "ESNext",
7 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
8 | "skipLibCheck": true,
9 |
10 | /* Bundler mode */
11 | "moduleResolution": "bundler",
12 | "allowImportingTsExtensions": true,
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "noEmit": true,
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src"]
24 | }
25 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | :root {
6 | --foreground-rgb: 0, 0, 0;
7 | --background-start-rgb: 214, 219, 220;
8 | --background-end-rgb: 255, 255, 255;
9 | }
10 |
11 | @media (prefers-color-scheme: dark) {
12 | :root {
13 | --foreground-rgb: 255, 255, 255;
14 | --background-start-rgb: 0, 0, 0;
15 | --background-end-rgb: 0, 0, 0;
16 | }
17 | }
18 |
19 | body {
20 | color: rgb(var(--foreground-rgb));
21 | background: linear-gradient(
22 | to bottom,
23 | transparent,
24 | rgb(var(--background-end-rgb))
25 | )
26 | rgb(var(--background-start-rgb));
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/bc-router-outlet.ts:
--------------------------------------------------------------------------------
1 | import {html} from 'lit';
2 | import {customElement} from 'lit/decorators.js';
3 | import {BitcoinConnectElement} from './BitcoinConnectElement';
4 | import {withTwind} from './twind/withTwind';
5 | import {routes} from './routes';
6 |
7 | @customElement('bc-router-outlet')
8 | export class RouterOutlet extends withTwind()(BitcoinConnectElement) {
9 | override render() {
10 | //TODO: r = routes[this._route](this._routeParams);
11 | return html`${routes[this._route]}
`;
12 | }
13 | }
14 |
15 | declare global {
16 | interface HTMLElementTagNameMap {
17 | 'bc-router-outlet': RouterOutlet;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/demos/html/bc-button.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | bc-button Demo
7 |
13 |
14 |
15 |
16 |
17 | <bc-button /> Demo
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demos/react/src/pages/ConnectDemo.tsx:
--------------------------------------------------------------------------------
1 | import {Connect} from '@getalby/bitcoin-connect-react';
2 | import toast, {Toaster} from 'react-hot-toast';
3 |
4 | export default function ConnectDemo() {
5 | return (
6 |
7 |
Connect Demo
8 |
9 | {
11 | console.log('WebLN connected', provider);
12 | toast('Connected!');
13 | }}
14 | onConnecting={() => toast('Connecting!')}
15 | onDisconnected={() => toast('Disconnected!')}
16 | onModalOpened={() => toast('Modal opened!')}
17 | onModalClosed={() => toast('Modal closed!')}
18 | />
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/demos/react/src/pages/Home.tsx:
--------------------------------------------------------------------------------
1 | import {Link} from 'react-router-dom';
2 |
3 | export default function Home() {
4 | return (
5 |
6 |
Bitcoin Connect React Demo
7 |
8 |
9 |
10 | Basic Button Demo
11 |
12 |
13 | Payment Button Demo
14 |
15 |
16 | Connect Component Demo
17 |
18 |
19 | Payment Component Demo
20 |
21 |
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/src/connectors/index.ts:
--------------------------------------------------------------------------------
1 | import {ExtensionConnector} from './ExtensionConnector';
2 | import {LnbitsConnector} from './LnbitsConnector';
3 | import {LNCConnector} from './LNCConnector';
4 | import {NWCConnector} from './NWCConnector';
5 |
6 | export const connectors = {
7 | 'extension.generic': ExtensionConnector,
8 | 'nwc.alby': NWCConnector,
9 | 'nwc.albyhub': NWCConnector,
10 | 'nwc.generic': NWCConnector,
11 | 'nwc.lnfi': NWCConnector,
12 | 'nwc.coinos': NWCConnector,
13 | 'nwc.flash': NWCConnector,
14 | 'nwc.primal': NWCConnector,
15 | 'nwc.cashume': NWCConnector,
16 | 'nwc.lnbits': NWCConnector,
17 | 'nwc.rizful': NWCConnector,
18 | lnbits: LnbitsConnector,
19 | lnc: LNCConnector,
20 | };
21 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/components/BitcoinConnectClientWrapper.tsx:
--------------------------------------------------------------------------------
1 | import dynamic from 'next/dynamic';
2 | const Button = dynamic(
3 | () => import('@getalby/bitcoin-connect-react').then((mod) => mod.Button),
4 | {
5 | ssr: false,
6 | }
7 | );
8 |
9 | import React from 'react';
10 |
11 | export function BitcoinConnectClientWrapper() {
12 | return (
13 | <>
14 |
15 | {
17 | const launchModal = await import(
18 | '@getalby/bitcoin-connect-react'
19 | ).then((mod) => mod.launchModal);
20 | launchModal();
21 | }}
22 | >
23 | Launch modal
24 |
25 | >
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/demos/nextjs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "jsx": "preserve",
15 | "incremental": true,
16 | "plugins": [
17 | {
18 | "name": "next"
19 | }
20 | ],
21 | "paths": {
22 | "@/*": ["./*"]
23 | }
24 | },
25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 | "exclude": ["node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------
/demos/react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
6 | "module": "ESNext",
7 | "skipLibCheck": true,
8 |
9 | /* Bundler mode */
10 | "moduleResolution": "bundler",
11 | "allowImportingTsExtensions": true,
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "noEmit": true,
15 | "jsx": "react-jsx",
16 |
17 | /* Linting */
18 | "strict": true,
19 | "noUnusedLocals": true,
20 | "noUnusedParameters": true,
21 | "noFallthroughCasesInSwitch": true
22 | },
23 | "include": ["src"],
24 | "references": [{ "path": "./tsconfig.node.json" }]
25 | }
26 |
--------------------------------------------------------------------------------
/demos/nextjs/app/components/BitcoinConnectClientWrapper.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import dynamic from 'next/dynamic';
4 | const Button = dynamic(
5 | () => import('@getalby/bitcoin-connect-react').then((mod) => mod.Button),
6 | {
7 | ssr: false,
8 | }
9 | );
10 | import React from 'react';
11 |
12 | export function BitcoinConnectClientWrapper() {
13 | return (
14 | <>
15 |
16 | {
18 | const launchModal = await import(
19 | '@getalby/bitcoin-connect-react'
20 | ).then((mod) => mod.launchModal);
21 | launchModal();
22 | }}
23 | >
24 | Launch modal
25 |
26 | >
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/demos/nextjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@getalby/bitcoin-connect-react": "^3.8.1",
13 | "next": "14.0.4",
14 | "react": "^18",
15 | "react-dom": "^18"
16 | },
17 | "devDependencies": {
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.0.4",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-legacy",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@getalby/bitcoin-connect-react": "^3.2.2",
13 | "next": "14.0.4",
14 | "react": "^18",
15 | "react-dom": "^18"
16 | },
17 | "devDependencies": {
18 | "@types/node": "^20",
19 | "@types/react": "^18",
20 | "@types/react-dom": "^18",
21 | "autoprefixer": "^10.0.1",
22 | "eslint": "^8",
23 | "eslint-config-next": "14.0.4",
24 | "postcss": "^8",
25 | "tailwindcss": "^3.3.0",
26 | "typescript": "^5"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-generic-nwc-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {nwcIcon} from '../icons/connectors/nwcIcon';
3 | import {ConnectorElement} from './ConnectorElement';
4 | import store from '../../state/store';
5 |
6 | export const genericConnectorTitle = 'NWC';
7 |
8 | @customElement('bc-nwc-connector')
9 | export class GenericNWCConnector extends ConnectorElement {
10 | constructor() {
11 | super('nwc.generic', genericConnectorTitle, '#ffffff', nwcIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/nwc');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-nwc-connector': GenericNWCConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/demos/react/src/pages/BasicButtonDemo.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Button} from '@getalby/bitcoin-connect-react';
3 | import toast, {Toaster} from 'react-hot-toast';
4 |
5 | export default function BasicButtonDemo() {
6 | return (
7 |
8 |
Basic Button Demo
9 |
10 | {
12 | console.log('WebLN connected', provider);
13 | toast('Connected!');
14 | }}
15 | onConnecting={() => toast('Connecting!')}
16 | onDisconnected={() => toast('Disconnected!')}
17 | onModalOpened={() => toast('Modal opened!')}
18 | onModalClosed={() => toast('Modal closed!')}
19 | />
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-lnbits-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {lnbitsIcon} from '../icons/connectors/lnbitsIcon';
5 |
6 | export const lnbitsConnectorTitle = 'LNbits';
7 |
8 | @customElement('bc-lnbits-connector')
9 | export class LNBitsConnector extends ConnectorElement {
10 | constructor() {
11 | super('lnbits', lnbitsConnectorTitle, '#673ab7', lnbitsIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/lnbits');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-lnbits-connector': LNBitsConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-lnfi-nwc-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {lnfiIcon} from '../icons/connectors/lnfiIcon';
3 | import {ConnectorElement} from './ConnectorElement';
4 | import store from '../../state/store';
5 |
6 | export const lnfiConnectorTitle = 'LN Link';
7 |
8 | @customElement('bc-lnfi-nwc-connector')
9 | export class LnfiNWCConnector extends ConnectorElement {
10 | constructor() {
11 | super('nwc.generic', lnfiConnectorTitle, '#ffffff', lnfiIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/lnfi');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-lnfi-nwc-connector': LnfiNWCConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-rizful-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {rizfulIcon} from '../icons/connectors/rizfulIcon';
5 |
6 | export const rizfulConnectorTitle = 'Rizful';
7 |
8 | @customElement('bc-rizful-connector')
9 | export class RizfulConnector extends ConnectorElement {
10 | constructor() {
11 | super('nwc.rizful', rizfulConnectorTitle, '#000000', rizfulIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/rizful');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-rizful-connector': RizfulConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-primal-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {primalIcon} from '../icons/connectors/primalIcon';
5 |
6 | export const primalConnectorTitle = 'Primal Mobile';
7 |
8 | @customElement('bc-primal-connector')
9 | export class PrimalConnector extends ConnectorElement {
10 | constructor() {
11 | super('nwc.primal', primalConnectorTitle, '#000000', primalIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/primal');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-primal-connector': PrimalConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-flash-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {flashWalletIcon} from '../icons/connectors/flashWalleticon';
5 | export const flashConnectorTitle = 'Flash Wallet';
6 |
7 | @customElement('bc-flash-connector')
8 | export class FlashConnector extends ConnectorElement {
9 | constructor() {
10 | super('nwc.flash', flashConnectorTitle, '#000000', flashWalletIcon);
11 | }
12 |
13 | protected async _onClick() {
14 | store.getState().pushRoute('/flash-wallet');
15 | }
16 | }
17 |
18 | declare global {
19 | interface HTMLElementTagNameMap {
20 | 'bc-flash-connector': FlashConnector;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-alby-hub-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {albyhubIcon} from '../icons/connectors/albyHubIcon';
5 |
6 | export const albyHubConnectorTitle = 'Alby Hub';
7 |
8 | @customElement('bc-alby-hub-connector')
9 | export class AlbyHubConnector extends ConnectorElement {
10 | constructor() {
11 | super('nwc.albyhub', albyHubConnectorTitle, '#000000', albyhubIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/alby-hub');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-alby-hub-connector': AlbyHubConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-cashu-me-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {cashuMeIcon} from '../icons/connectors/cashuMeIcon';
5 |
6 | export const cashuMeConnectorTitle = 'Cashu.me';
7 |
8 | @customElement('bc-cashu-me-connector')
9 | export class CashuMeConnector extends ConnectorElement {
10 | constructor() {
11 | super('nwc.cashume', cashuMeConnectorTitle, '#7f38ca', cashuMeIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/cashu-me');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-cashu-me-connector': CashuMeConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-lnbits-nwc-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {lnbitsIcon} from '../icons/connectors/lnbitsIcon';
5 |
6 | export const lnbitsNWCConnectorTitle = 'LNbits NWC Plugin';
7 |
8 | @customElement('bc-lnbits-nwc-connector')
9 | export class LNbitsNWCConnector extends ConnectorElement {
10 | constructor() {
11 | super('lnbits', lnbitsNWCConnectorTitle, '#673ab7', lnbitsIcon);
12 | }
13 |
14 | protected async _onClick() {
15 | store.getState().pushRoute('/lnbits-nwc');
16 | }
17 | }
18 |
19 | declare global {
20 | interface HTMLElementTagNameMap {
21 | 'bc-lnbits-nwc-connector': LNbitsNWCConnector;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/icons/disconnectIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 | // - add class="hover-right" to the second path for the arrow animation
6 | export const disconnectIcon = svg`
7 |
8 |
9 |
10 | `;
11 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Adding a new Connector component
4 |
5 | A connector component is a web component that will be displayed in the modal. You can customize the name, color, icon and functionality that will happen when the component is clicked.
6 |
7 | See [existing connector components](src/components/connectors/index.ts)
8 |
9 | Make sure to add your new connector component to the [connector list](src/components/bc-connector-list.ts)
10 |
11 | ## Adding a new connector
12 |
13 | A connector exposes a WebLN object for the web application.
14 |
15 | See [existing connectors](src/connectors/index.ts)
16 |
17 | ## Adding a new wrapper package
18 |
19 | A wrapper package simplifies integration of Bitcoin Connect with different web frameworks.
20 |
21 | See [React](/react)
22 |
--------------------------------------------------------------------------------
/react/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "moduleResolution": "node",
6 | "jsx": "react",
7 | "declaration": true,
8 | "sourceMap": true,
9 | "rootDir": "src",
10 | "outDir": "dist",
11 | "strict": true,
12 | "noUnusedLocals": true,
13 | "noUnusedParameters": true,
14 | "noImplicitReturns": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "noImplicitAny": true,
17 | "noImplicitThis": true,
18 | "allowSyntheticDefaultImports": true,
19 | "experimentalDecorators": true,
20 | "forceConsistentCasingInFileNames": true,
21 | "noImplicitOverride": true,
22 | "useDefineForClassFields": false
23 | },
24 | "include": ["src"],
25 | "exclude": ["node_modules", "dist"]
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/templates/innerBorder.ts:
--------------------------------------------------------------------------------
1 | import {html} from 'lit';
2 | import {classes} from '../css/classes';
3 |
4 | export function innerBorder() {
5 | return html`
`;
10 | }
11 |
12 | export function innerBorderBranded() {
13 | return html`
`;
18 | }
19 |
20 | export function innerBorderTertiary() {
21 | return html`
`;
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/icons/connectors/lnfiIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - set class="w-10 h-10"
5 |
6 | export const lnfiIcon = svg`
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | `;
17 |
--------------------------------------------------------------------------------
/dev/vite/button.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Bitcoin Connect Demo
7 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/react/src/hooks/useOnPaid.ts:
--------------------------------------------------------------------------------
1 | import {SendPaymentResponse} from '@webbtc/webln-types';
2 | import React from 'react';
3 |
4 | export function useOnPaid(
5 | onPaid?: (response: SendPaymentResponse) => void,
6 | payment?: SendPaymentResponse
7 | ) {
8 | React.useEffect(() => {
9 | const onPaidEventHandler = (event: Event) => {
10 | onPaid?.((event as CustomEvent).detail);
11 | };
12 | window.addEventListener('bc:onpaid', onPaidEventHandler);
13 |
14 | if (payment) {
15 | // TODO: remove once bc-send-payment accepts preimage
16 | window.dispatchEvent(
17 | new CustomEvent('bc:onpaid', {
18 | detail: payment,
19 | })
20 | );
21 | }
22 |
23 | return () => {
24 | window.removeEventListener('bc:onpaid', onPaidEventHandler);
25 | };
26 | }, [onPaid, payment]);
27 | }
28 |
--------------------------------------------------------------------------------
/dev/vite/connector-list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Bitcoin Connect Demo
7 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/components/icons/satIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 |
6 | export const satIcon = svg`
7 |
8 | `;
9 |
--------------------------------------------------------------------------------
/src/components/icons/walletIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 |
6 | export const walletIcon = svg`
7 |
8 |
9 | `;
10 |
--------------------------------------------------------------------------------
/demos/react/src/App.tsx:
--------------------------------------------------------------------------------
1 | import {BrowserRouter, Routes, Route} from 'react-router-dom';
2 | import {init} from '@getalby/bitcoin-connect-react';
3 | import Home from './pages/Home';
4 | import BasicButtonDemo from './pages/BasicButtonDemo';
5 | import PaymentButtonDemo from './pages/PaymentButtonDemo';
6 | import ConnectDemo from './pages/ConnectDemo';
7 | import PaymentDemo from './pages/PaymentDemo';
8 |
9 | init({
10 | appName: 'Bitcoin Connect (React Demo)',
11 | });
12 |
13 | function App() {
14 | return (
15 |
16 |
17 | } />
18 | } />
19 | } />
20 | } />
21 | } />
22 |
23 |
24 | );
25 | }
26 |
27 | export default App;
28 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {NostrWebLNProvider} from '@getalby/sdk';
2 | import {LNCWebLNProvider} from './connectors/LNCConnector';
3 | import {LnbitsWebLNProvider} from './connectors/LnbitsConnector';
4 | import './state/boot';
5 |
6 | export * from './components/bc-button';
7 | export * from './components/bc-pay-button';
8 | export * from './components/bc-modal';
9 | export * from './components/bc-connector-list';
10 | export * from './components/bc-balance';
11 | export * from './components/bc-currency-switcher';
12 | export * from './components/pages/bc-send-payment';
13 | export * from './components/connectors/index';
14 | export * from './components/flows/bc-connect';
15 | export * from './components/flows/bc-payment';
16 | export * from './state/store';
17 | export * from './api';
18 |
19 | export const WebLNProviders = {
20 | NostrWebLNProvider: NostrWebLNProvider,
21 | LNCWebLNProvider,
22 | LnbitsWebLNProvider,
23 | };
24 |
25 | export * from './types/PaymentMethods';
26 |
--------------------------------------------------------------------------------
/src/components/internal/bci-connecting.ts:
--------------------------------------------------------------------------------
1 | import {LitElement, html} from 'lit';
2 | import {withTwind} from '../twind/withTwind';
3 | import {customElement} from 'lit/decorators.js';
4 | import {classes} from '../css/classes';
5 | import {waitingIcon} from '../icons/waitingIcon';
6 | import {disconnectSection} from '../templates/disconnectSection';
7 |
8 | @customElement('bci-connecting')
9 | export class Connecting extends withTwind()(LitElement) {
10 | override render() {
11 | return html`
12 |
13 | ${waitingIcon(`w-20 h-20 ${classes['text-neutral-tertiary']} mb-4`)}
14 |
15 | Connecting to wallet...
16 |
17 | ${disconnectSection(undefined)}
18 |
19 | `;
20 | }
21 | }
22 |
23 | declare global {
24 | interface HTMLElementTagNameMap {
25 | 'bci-connecting': Connecting;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2020",
4 | "module": "es2020",
5 | "lib": ["es2020", "DOM", "DOM.Iterable"],
6 | "declaration": true,
7 | "declarationMap": false,
8 | "sourceMap": false,
9 | "outDir": "./",
10 | "rootDir": "./src",
11 | "strict": true,
12 | "skipLibCheck": true,
13 | "noUnusedLocals": true,
14 | "noUnusedParameters": true,
15 | "noImplicitReturns": true,
16 | "noFallthroughCasesInSwitch": true,
17 | "noImplicitAny": true,
18 | "noImplicitThis": true,
19 | "moduleResolution": "node",
20 | "allowSyntheticDefaultImports": true,
21 | "experimentalDecorators": true,
22 | "forceConsistentCasingInFileNames": true,
23 | "noImplicitOverride": true,
24 | "useDefineForClassFields": false,
25 | "plugins": [
26 | {
27 | "name": "ts-lit-plugin",
28 | "strict": true
29 | }
30 | ]
31 | },
32 | "include": ["src/**/*.ts"],
33 | "exclude": []
34 | }
35 |
--------------------------------------------------------------------------------
/src/components/icons/linkIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 | // - add class="hover-right" to the second path for the arrow animation
6 | export const linkIcon = svg`
7 |
8 |
9 | `;
10 |
--------------------------------------------------------------------------------
/demos/html/README.md:
--------------------------------------------------------------------------------
1 | ## Previewing the Demos
2 |
3 | ### Option 1: Open HTML Files Directly
4 |
5 | You can open any of the demo files in your browser by double-clicking or using “Open with Browser”:
6 |
7 | * [`bc-button.html`](./bc-button.html)
8 | * [`bc-api-usage.html`](./bc-api-usage.html)
9 | * [`bc-pay-button.html`](./bc-pay-button.html)
10 |
11 | ---
12 |
13 | ### Option 2: Run a Local Development Server
14 |
15 | We recommend using a local server for hot reloading and better cross-origin behavior (especially for web components and modules).
16 |
17 | #### 1. Install dependencies
18 |
19 | ```bash
20 | yarn install
21 | ````
22 |
23 | #### 2. Start the dev server
24 |
25 | Use any of the following scripts to preview a specific demo:
26 |
27 | ```bash
28 | yarn bc-button # Runs bc-button.html
29 | yarn bc-api-usage # Runs bc-api-usage.html
30 | yarn bc-pay-button # Runs bc-pay-button.html
31 | ```
32 |
33 |
34 | You can also manually visit any file at `http://localhost:8000/demos/html/.html`
35 |
36 |
--------------------------------------------------------------------------------
/src/components/icons/connectors/flashWalleticon.ts:
--------------------------------------------------------------------------------
1 | import { svg } from "lit";
2 |
3 | export const flashWalletIcon = svg` `
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-lnc-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import {lncIcon} from '../icons/connectors/lncIcon';
4 | import {getLNC} from '../../connectors/LNCConnector';
5 |
6 | @customElement('bc-lnc-connector')
7 | export class LNCConnector extends ConnectorElement {
8 | constructor() {
9 | super('lnc', 'Lightning Node Connect', '#101727', lncIcon);
10 | }
11 |
12 | protected async _onClick() {
13 | // TODO: improve UX for entering pairing phrase, allow scanning QR code?
14 | const pairingPhrase = window.prompt('Enter pairing phrase');
15 | if (!pairingPhrase) {
16 | return;
17 | }
18 |
19 | const lnc = await getLNC();
20 | if (!lnc) {
21 | throw new Error('LNC not supported');
22 | }
23 | lnc.credentials.pairingPhrase = pairingPhrase;
24 |
25 | this._connect({});
26 | }
27 | }
28 |
29 | declare global {
30 | interface HTMLElementTagNameMap {
31 | 'bc-lnc-connector': LNCConnector;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2 | # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3 |
4 | # NOTE: this is currently disabled and published manually
5 | name: Publish package
6 |
7 | on:
8 | #release:
9 | # types: [created]
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 | - uses: actions/setup-node@v3
17 | with:
18 | node-version: 18
19 | - run: yarn install --frozen-lockfile
20 |
21 | publish-npm:
22 | needs: build
23 | runs-on: ubuntu-latest
24 | steps:
25 | - uses: actions/checkout@v3
26 | - uses: actions/setup-node@v3
27 | with:
28 | node-version: 18
29 | registry-url: https://registry.npmjs.org/
30 | - run: yarn install --frozen-lockfile
31 | - run: npm publish
32 | env:
33 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
34 |
--------------------------------------------------------------------------------
/demos/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@getalby/bitcoin-connect-react": "^3.8.1",
14 | "@getalby/lightning-tools": "^5.1.2",
15 | "react": "^19.1.1",
16 | "react-dom": "^19.1.1",
17 | "react-hot-toast": "^2.4.1",
18 | "react-router-dom": "^7.1.5"
19 | },
20 | "devDependencies": {
21 | "@types/react": "^19.1.12",
22 | "@types/react-dom": "^19.1.9",
23 | "@typescript-eslint/eslint-plugin": "^8.42.0",
24 | "@typescript-eslint/parser": "^8.42.0",
25 | "@vitejs/plugin-react-swc": "^4.0.1",
26 | "@webbtc/webln-types": "^3.0.0",
27 | "eslint": "^9.34.0",
28 | "eslint-plugin-react-hooks": "^5.2.0",
29 | "eslint-plugin-react-refresh": "^0.4.20",
30 | "typescript": "^5.9.2",
31 | "vite": "^7.1.4"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/state/boot.ts:
--------------------------------------------------------------------------------
1 | import {ConnectorConfig} from '../types/ConnectorConfig';
2 | import store from './store';
3 |
4 | function loadConfig() {
5 | const configJson = window.localStorage.getItem('bc:config');
6 | if (configJson) {
7 | const config = JSON.parse(configJson) as ConnectorConfig;
8 | store.getState().connect(config, {redirectTo: '/start'});
9 | }
10 |
11 | const currency = window.localStorage.getItem('bc:currency');
12 | if (currency) {
13 | store.getState().setCurrency(currency);
14 | }
15 | }
16 |
17 | function addEventListeners() {
18 | window.addEventListener('webln:enabled', () => {
19 | if (!store.getState().connecting) {
20 | // webln was enabled from outside
21 | // TODO: use the same name and logic for figuring out what extension as the extension connector
22 | store.getState().connect(
23 | {
24 | connectorName: 'Extension',
25 | connectorType: 'extension.generic',
26 | },
27 | {redirectTo: '/start'}
28 | );
29 | }
30 | });
31 | }
32 |
33 | if (globalThis.window) {
34 | loadConfig();
35 | addEventListeners();
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/templates/disconnectSection.ts:
--------------------------------------------------------------------------------
1 | import {html} from 'lit';
2 | import {classes} from '../css/classes';
3 | import {disconnectIcon} from '../icons/disconnectIcon';
4 | import store from '../../state/store';
5 |
6 | export function disconnectSection(connectorName: string | undefined) {
7 | return html`
8 | ${connectorName
9 | ? html`Connected through
11 | ${connectorName} `
13 | : null}
14 |
15 |
21 | ${disconnectIcon}
22 | Disconnect
25 |
26 |
`;
27 | }
28 |
29 | function handleDisconnect() {
30 | // disconnect after closing modal
31 | // to avoid flash on modal screen
32 | store.getState().setModalOpen(false);
33 | setTimeout(() => {
34 | store.getState().disconnect();
35 | }, 200);
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Alby contributors (https://getalby.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@getalby/bitcoin-connect-react",
3 | "version": "3.11.5",
4 | "type": "module",
5 | "source": "src/index.ts",
6 | "main": "./dist/index.cjs",
7 | "module": "./dist/index.module.js",
8 | "unpkg": "./dist/index.umd.js",
9 | "types": "./dist/index.d.ts",
10 | "exports": {
11 | "require": "./dist/index.cjs",
12 | "types": "./dist/index.d.ts",
13 | "default": "./dist/index.modern.js"
14 | },
15 | "license": "MIT",
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/getAlby/bitcoin-connect.git",
19 | "directory": "react"
20 | },
21 | "files": [
22 | "dist/**/*"
23 | ],
24 | "scripts": {
25 | "dev": "microbundle --globals react=React --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react watch",
26 | "prepack": "yarn build",
27 | "build": "microbundle --globals react=React --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react"
28 | },
29 | "dependencies": {
30 | "@getalby/bitcoin-connect": "^3.11.5"
31 | },
32 | "devDependencies": {
33 | "@types/react": "^18.2.21",
34 | "microbundle": "^0.15.1"
35 | },
36 | "peerDependencies": {
37 | "react": ">=18.2.0"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/bc-modal.ts:
--------------------------------------------------------------------------------
1 | import {html} from 'lit';
2 | import {customElement} from 'lit/decorators.js';
3 | import {BitcoinConnectElement} from './BitcoinConnectElement';
4 | import './bc-router-outlet.js';
5 | import {withTwind} from './twind/withTwind';
6 | import './bc-modal-header';
7 | import {closeModal} from '../api';
8 |
9 | @customElement('bc-modal')
10 | export class Modal extends withTwind()(BitcoinConnectElement) {
11 | override render() {
12 | return html` `;
26 | }
27 |
28 | private _handleClose = () => {
29 | closeModal();
30 | };
31 | }
32 |
33 | declare global {
34 | interface HTMLElementTagNameMap {
35 | 'bc-modal': Modal;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/components/icons/connectors/albyGoIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | export const albyGoIcon = svg` `;
4 |
--------------------------------------------------------------------------------
/demos/nextjs/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demos/nextjs-legacy/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/react/src/components/Payment.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import '@getalby/bitcoin-connect';
3 | import {ComponentProps} from '../types/ComponentProps';
4 | import {useCoreEvents} from '../hooks/useCoreEvents';
5 | import {SendPaymentResponse} from '@webbtc/webln-types';
6 | import {useOnPaid} from '../hooks/useOnPaid';
7 | import {PaymentMethods} from '@getalby/bitcoin-connect';
8 |
9 | type PaymentProps = ComponentProps & {
10 | /**
11 | * Bolt 11 invoice to pay
12 | */
13 | invoice: string;
14 | /**
15 | * Supported payment methods in payment flow
16 | */
17 | paymentMethods?: PaymentMethods;
18 | /**
19 | * @param response response of the WebLN send payment call
20 | */
21 | onPaid?: (response: SendPaymentResponse) => void;
22 | /**
23 | * Mark that an external payment was made
24 | */
25 | payment?: SendPaymentResponse;
26 | };
27 |
28 | export const Payment: React.FC = (props) => {
29 | useCoreEvents(props);
30 |
31 | const {onPaid, payment} = props;
32 | useOnPaid(onPaid, payment);
33 |
34 | return (
35 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
36 | // @ts-ignore
37 |
44 | );
45 | };
46 |
--------------------------------------------------------------------------------
/src/components/bc-navbar.ts:
--------------------------------------------------------------------------------
1 | import {html} from 'lit';
2 | import {customElement, property} from 'lit/decorators.js';
3 | import {BitcoinConnectElement} from './BitcoinConnectElement';
4 | import {withTwind} from './twind/withTwind';
5 | import store from '../state/store';
6 | import {backIcon} from './icons/backIcon';
7 | import {classes} from './css/classes';
8 |
9 | @customElement('bc-navbar')
10 | export class Navbar extends withTwind()(BitcoinConnectElement) {
11 | @property()
12 | heading?: string;
13 |
14 | override render() {
15 | return html`
18 |
19 |
25 | ${backIcon}
26 |
27 |
28 |
29 | ${this.heading}
30 |
31 |
`;
32 | }
33 |
34 | private _goBack = () => {
35 | store.getState().popRoute();
36 | store.getState().setError(undefined);
37 | };
38 | }
39 |
40 | declare global {
41 | interface HTMLElementTagNameMap {
42 | 'bc-navbar': Navbar;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/icons/connectors/coinosIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | export const coinosIcon = svg` `;
4 |
--------------------------------------------------------------------------------
/src/components/icons/copyIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 |
6 | export const copyIcon = svg`
7 |
8 | `;
9 |
--------------------------------------------------------------------------------
/src/components/pages/bc-connected.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {BitcoinConnectElement} from '../BitcoinConnectElement';
3 | import {withTwind} from '../twind/withTwind';
4 | import {html} from 'lit';
5 | import '../internal/bci-button';
6 | import {successAnimation} from '../images/success.js';
7 | import store from '../../state/store';
8 | import {closeModal} from '../../api';
9 | import {classes} from '../css/classes';
10 |
11 | @customElement('bc-connected')
12 | export class ConnectedPage extends withTwind()(BitcoinConnectElement) {
13 | private _timeout: NodeJS.Timeout | undefined;
14 | override connectedCallback(): void {
15 | super.connectedCallback();
16 | this._timeout = setTimeout(() => {
17 | closeModal();
18 | store.setState({
19 | route: '/start',
20 | });
21 | }, 3000);
22 | }
23 |
24 | override disconnectedCallback(): void {
25 | super.disconnectedCallback();
26 | if (this._timeout) {
27 | clearTimeout(this._timeout);
28 | }
29 | }
30 |
31 | override render() {
32 | return html`
37 |
Connected!
38 | ${successAnimation}
39 |
`;
40 | }
41 | }
42 |
43 | declare global {
44 | interface HTMLElementTagNameMap {
45 | 'bc-connected': ConnectedPage;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/dev/vite/pay-button.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Bitcoin Connect Demo
7 |
22 |
25 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/components/connectors/bc-coinos-connector.ts:
--------------------------------------------------------------------------------
1 | import {customElement} from 'lit/decorators.js';
2 | import {ConnectorElement} from './ConnectorElement';
3 | import store from '../../state/store';
4 | import {coinosIcon} from '../icons/connectors/coinosIcon';
5 | import {NWCClient} from '@getalby/sdk';
6 |
7 | export const coinosConnectorTitle = 'Coinos';
8 |
9 | @customElement('bc-coinos-connector')
10 | export class CoinosConnector extends ConnectorElement {
11 | constructor() {
12 | super('nwc.coinos', coinosConnectorTitle, '#ffffff', coinosIcon);
13 | }
14 |
15 | protected async _onClick() {
16 | try {
17 | const providerConfig =
18 | store.getState().bitcoinConnectConfig.providerConfig;
19 | const nwcClient = await NWCClient.fromAuthorizationUrl(
20 | 'https://coinos.io/apps/new',
21 | {
22 | ...(providerConfig?.nwc?.authorizationUrlOptions || {}),
23 | name: this._appName,
24 | }
25 | );
26 | nwcClient.close();
27 | // TODO: it makes no sense to connect again
28 | await store.getState().connect({
29 | nwcUrl: nwcClient.nostrWalletConnectUrl,
30 | connectorName: 'Coinos',
31 | connectorType: 'nwc.coinos',
32 | });
33 | } catch (error) {
34 | console.error(error);
35 | alert('' + error);
36 | }
37 | }
38 | }
39 |
40 | declare global {
41 | interface HTMLElementTagNameMap {
42 | 'bc-coinos-connector': CoinosConnector;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/icons/copiedIcon.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | // WARNING: if replacing this icon make sure to:
4 | // - change all colors to "currentColor"
5 |
6 | export const copiedIcon = svg`
7 |
8 |
9 | `;
10 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": [
4 | "eslint:recommended",
5 | "plugin:@typescript-eslint/eslint-recommended",
6 | "plugin:@typescript-eslint/recommended"
7 | ],
8 | "parser": "@typescript-eslint/parser",
9 | "parserOptions": {
10 | "ecmaVersion": 2020,
11 | "sourceType": "module"
12 | },
13 | "plugins": ["@typescript-eslint"],
14 | "env": {
15 | "browser": true
16 | },
17 | "rules": {
18 | "no-prototype-builtins": "off",
19 | "@typescript-eslint/ban-types": "off",
20 | "@typescript-eslint/explicit-function-return-type": "off",
21 | "@typescript-eslint/explicit-module-boundary-types": "off",
22 | "@typescript-eslint/no-explicit-any": "error",
23 | "@typescript-eslint/no-empty-function": "off",
24 | "@typescript-eslint/no-non-null-assertion": "off",
25 | "@typescript-eslint/no-unused-vars": [
26 | "warn",
27 | {
28 | "argsIgnorePattern": "^_"
29 | }
30 | ]
31 | },
32 | "overrides": [
33 | {
34 | "files": ["**/*.ts"]
35 | },
36 | {
37 | "files": ["web-test-runner.config.js"],
38 | "env": {
39 | "node": true
40 | }
41 | },
42 | {
43 | "files": [
44 | "*_test.ts",
45 | "**/custom_typings/*.ts",
46 | "packages/labs/ssr/src/test/integration/tests/**",
47 | "packages/labs/ssr/src/lib/util/parse5-utils.ts"
48 | ],
49 | "rules": {
50 | "@typescript-eslint/no-explicit-any": "off"
51 | }
52 | }
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/react/src/hooks/useCoreEvents.ts:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {ComponentProps} from '../types/ComponentProps';
3 | import {
4 | onConnected,
5 | onConnecting,
6 | onDisconnected,
7 | onModalClosed,
8 | onModalOpened,
9 | } from '@getalby/bitcoin-connect';
10 |
11 | export function useCoreEvents(props: ComponentProps) {
12 | React.useEffect(() => {
13 | if (props.onConnected) {
14 | const unsub = onConnected(props.onConnected);
15 |
16 | return () => {
17 | unsub();
18 | };
19 | }
20 | return () => {};
21 | }, []);
22 | React.useEffect(() => {
23 | if (props.onConnecting) {
24 | const unsub = onConnecting(props.onConnecting);
25 |
26 | return () => {
27 | unsub();
28 | };
29 | }
30 | return () => {};
31 | }, []);
32 | React.useEffect(() => {
33 | if (props.onDisconnected) {
34 | const unsub = onDisconnected(props.onDisconnected);
35 |
36 | return () => {
37 | unsub();
38 | };
39 | }
40 | return () => {};
41 | }, []);
42 | React.useEffect(() => {
43 | if (props.onModalOpened) {
44 | const unsub = onModalOpened(props.onModalOpened);
45 |
46 | return () => {
47 | unsub();
48 | };
49 | }
50 | return () => {};
51 | }, []);
52 | React.useEffect(() => {
53 | if (props.onModalClosed) {
54 | const unsub = onModalClosed(props.onModalClosed);
55 |
56 | return () => {
57 | unsub();
58 | };
59 | }
60 | return () => {};
61 | }, []);
62 | }
63 |
--------------------------------------------------------------------------------
/src/components/css/classes.ts:
--------------------------------------------------------------------------------
1 | export const classes = {
2 | interactive:
3 | 'transition-all hover:brightness-90 dark:hover:brightness-110 active:scale-95 cursor-pointer',
4 | 'hover-animation': 'hover-animation',
5 |
6 | // text colors
7 | 'text-brand': 'text-brand-light dark:text-brand-dark',
8 | 'text-brand-mixed': 'text-brand-mixed-light dark:text-brand-mixed-dark',
9 | 'text-brand-button-text':
10 | 'text-brand-button-text-light dark:text-brand-button-text-dark',
11 | 'text-foreground': 'text-foreground-light dark:text-foreground-dark',
12 | 'text-neutral-primary':
13 | 'text-neutral-primary-light dark:text-neutral-primary-dark',
14 | 'text-neutral-secondary':
15 | 'text-neutral-secondary-light dark:text-neutral-secondary-dark',
16 | 'text-neutral-tertiary':
17 | 'text-neutral-tertiary-light dark:text-neutral-tertiary-dark',
18 |
19 | // background colors
20 | 'bg-brand': 'bg-brand-light dark:bg-brand-dark',
21 | 'bg-background': 'bg-background-light dark:bg-background-dark',
22 | 'bg-foreground': 'bg-foreground-light dark:bg-foreground-dark',
23 | 'bg-glass': 'bg-glass-light dark:bg-glass-dark',
24 |
25 | // border colors
26 | 'border-brand': 'border-brand-light dark:border-brand-dark',
27 | 'border-brand-mixed': 'border-brand-mixed-light dark:border-brand-mixed-dark',
28 | 'border-neutral-secondary':
29 | 'border-neutral-secondary-light dark:border-neutral-secondary-dark',
30 | 'border-neutral-tertiary':
31 | 'border-neutral-tertiary-light dark:border-neutral-tertiary-dark',
32 | };
33 |
--------------------------------------------------------------------------------
/src/components/images/success.ts:
--------------------------------------------------------------------------------
1 | import {svg} from 'lit';
2 |
3 | export const successAnimation = svg`
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | `;
23 |
--------------------------------------------------------------------------------
/react/src/components/PayButton.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import '@getalby/bitcoin-connect';
3 | import {PaymentMethods} from '@getalby/bitcoin-connect';
4 | import {ComponentProps} from '../types/ComponentProps';
5 | import {useCoreEvents} from '../hooks/useCoreEvents';
6 | import {SendPaymentResponse} from '@webbtc/webln-types';
7 | import {useOnPaid} from '../hooks/useOnPaid';
8 |
9 | type PayButtonProps = ComponentProps & {
10 | /**
11 | * Bolt 11 invoice to pay
12 | */
13 | invoice?: string;
14 | /**
15 | * Supported payment methods in payment flow
16 | */
17 | paymentMethods?: PaymentMethods;
18 | /**
19 | * @param response response of the WebLN send payment call
20 | */
21 | onPaid?: (response: SendPaymentResponse) => void;
22 | /**
23 | * Mark that an external payment was made
24 | */
25 | payment?: SendPaymentResponse;
26 |
27 | /**
28 | * Listen to when the pay button is clicked.
29 | * This is a good time to fetch an invoice to pay.
30 | */
31 | onClick?: () => void;
32 | };
33 |
34 | export const PayButton: React.FC = (props) => {
35 | useCoreEvents(props);
36 |
37 | const {onPaid, payment} = props;
38 | useOnPaid(onPaid, payment);
39 |
40 | return (
41 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment
42 | // @ts-ignore
43 |
51 | );
52 | };
53 |
--------------------------------------------------------------------------------
/dev/vite/button-deeplink.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Bitcoin Connect Demo
7 |
22 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/doc/MIGRATION_v3.md:
--------------------------------------------------------------------------------
1 | # V2 to V3 migration guide
2 |
3 | ## WebLN global object
4 |
5 | window.webln is no longer set by default. If you rely on WebLN being available in the global window object please add the following lines to a place in your application which will be called on every page:
6 |
7 | ```ts
8 | import {onConnected} from '@getalby/bitcoin-connect';
9 |
10 | onConnected((provider) => {
11 | window.webln = provider;
12 | });
13 | ```
14 |
15 | ## Init
16 |
17 | Attributes (such as `filters` and `appName` that were originally passed to individual components) have been moved to the new `init` function exposed by the Bitcoin Connect api.
18 |
19 | ```ts
20 | import {init} from '@getalby/bitcoin-connect-react';
21 |
22 | init({
23 | appName: 'My Lightning App', // your app name
24 | // filters: ["nwc"],
25 | // ...etc
26 | });
27 | ```
28 |
29 | ## `launchModal` for payments
30 |
31 | This has been moved to `launchPaymentModal`.
32 |
33 | ## Modal
34 |
35 | `` (or ` `) no longer needs to be rendered manually. Make sure to remove it so that the modal does not unexpectedly render on the page.
36 |
37 | > Make sure to set Bitcoin Connect css variables at the root (e.g. html/body selector) to ensure the modal uses the correct colors.
38 |
39 | ## Button
40 |
41 | Attributes have been moved from the button to the `init` function exposed by the API.
42 |
43 | ## Events
44 |
45 | New subscription methods are exposed on the Bitcoin Connect API (`onConnected` etc) replacing window events such as `bc:connected`.
46 |
47 | ## Browser / Pure HTML build
48 |
49 | Use `
51 |
52 |
53 |
54 |
55 |
56 |
57 |