Skip to content

Development

WoompaLoompa edited this page Jul 12, 2026 · 1 revision

Guide for developers working on the CLINK plugin.

Prerequisites

Repository Structure

btcpay-clink/
├── src/BTCPayServer.Plugins.Clink/
│   ├── Plugin.cs                          # Entry point - DI registration
│   ├── Controllers/
│   │   └── ClinkController.cs             # HTTP API endpoints
│   ├── Services/
│   │   ├── ClinkService.cs                # Settings + payment recording
│   │   ├── ClinkNostrBridge.cs            # Node.js bridge spawner
│   │   ├── ClinkLightningClient.cs        # ILightningClient implementation
│   │   ├── ClinkConnectionStringHandler.cs # Connection string parser
│   │   ├── NostrEventStore.cs             # Invoice ↔ Nostr event mapping
│   │   ├── NdebitRegistry.cs              # Invoice ↔ nDebit mapping
│   │   └── EmailNdebitStore.cs            # Email ↔ nDebit mapping
│   ├── Models/
│   │   ├── ClinkSettings.cs               # Store configuration model
│   │   ├── ClinkPaymentData.cs            # Payment tracking model
│   │   ├── PaymentNotification.cs         # Webhook payload model
│   │   └── NostrInvoiceResult.cs          # Bridge response models
│   ├── Views/Clink/
│   │   ├── Configure.cshtml               # Admin config page
│   │   ├── ClinkStoreNav.cshtml           # Store sidebar nav
│   │   ├── ClinkCheckoutPayment.cshtml    # Checkout ndebit UI
│   │   ├── LightningSetupCustom.cshtml    # Lightning setup option
│   │   └── NdebitSetup.cshtml             # Standalone ndebit page
│   ├── Resources/
│   │   ├── js/
│   │   │   ├── clink-payment.js           # Client-side ES module
│   │   │   └── clink-payment.min.js       # Built bundle
│   │   └── css/
│   │       └── clink-payment.css          # Checkout styles
│   ├── nostr/
│   │   ├── clink-bridge.mjs              # Nostr bridge source
│   │   ├── clink-bridge.bundle.mjs       # Bundled bridge (embedded)
│   │   └── test-*.mjs                    # Integration test scripts
│   ├── Data/
│   │   └── ClinkDbContext.cs              # EF Core DbContext
│   ├── package.json                       # JS dependencies
│   ├── build.mjs                          # esbuild config
│   └── BTCPayServer.Plugins.Clink.csproj  # .NET project file
├── plugin-env.sh                          # Dev environment setup
├── plugin-register.sh                     # Debug registration
└── submodules/btcpayserver/               # BTCPay Server source

Development Environment Setup

1. Clone with Submodules

git clone --recurse-submodules https://github.com/WoompaLoompa/btcpay-clink.git
cd btcpay-clink

If already cloned:

git submodule update --init --recursive

2. Set Environment Variables

source plugin-env.sh

This sets:

  • BTCPAY_DEV_PLUGIN_DIR — path to the plugin directory
  • ASPNETCORE_ENVIRONMENT=Development

3. Build JavaScript Bundle

cd src/BTCPayServer.Plugins.Clink
npm install
npm run build
cd ../..

4. Build the Plugin

dotnet build

5. Register for Debugging

./plugin-register.sh

This builds the plugin and writes the DLL path to submodules/btcpayserver/BTCPayServer/appsettings.dev.json under DEBUG_PLUGINS.

6. Run BTCPay Server

cd submodules/btcpayserver/BTCPayServer
dotnet run

The plugin will be loaded automatically from the DEBUG_PLUGINS path.

Building the JavaScript Bundle

The Nostr bridge (nostr/clink-bridge.mjs) is bundled using esbuild:

cd src/BTCPayServer.Plugins.Clink

# One-time build
npm run build

# Watch mode (rebuilds on changes)
npm run watch

esbuild Configuration

Option Value
Entry point nostr/clink-bridge.mjs
Output nostr/clink-bridge.bundle.mjs
Platform Node.js
Target Node 22
Format ESM
Externals ws, bufferutil, utf-8-validate

The bundled file is embedded in the DLL as an embedded resource and extracted to a temp directory at runtime.

Key Dependencies

JavaScript

Package Version Purpose
@shocknet/clink-sdk ^1.5.5 CLINK protocol SDK
bolt11 ^1.4.1 BOLT11 invoice decoding
esbuild ^0.25.0 JS bundler (dev)
nostr-tools (transitive) Nostr protocol

.NET

Reference Purpose
BTCPayServer.csproj BTCPay Server core (via submodule)
Npgsql PostgreSQL provider
NBitcoin Bitcoin primitives
EntityFrameworkCore ORM
Newtonsoft.Json JSON serialization

Testing

Integration Test Scripts

The nostr/test-*.mjs files are manual integration test scripts:

Script Purpose
test-nmanage.mjs Test nManage queries
test-nmanage2.mjs Test nManage invoice queries
test-nmanage3.mjs BOLT11 decoding + queries
test-listen.mjs Relay event listener
test-payment.mjs Full payment flow
test-payment2.mjs Payment with multi-filter

Run them with:

cd src/BTCPayServer.Plugins.Clink
node nostr/test-payment.mjs

Manual Testing

  1. Start BTCPay Server in development mode
  2. Create a store and enable CLINK
  3. Configure with a test offer string
  4. Create an invoice and verify the QR code appears
  5. Pay with a test wallet and verify payment confirmation

Plugin Architecture

Dependency Injection (Plugin.cs)

All services are registered as singletons:

services.AddSingleton<ClinkService>();
services.AddSingleton<ClinkNostrBridge>();
services.AddSingleton<NostrEventStore>();
services.AddSingleton<NdebitRegistry>();
services.AddSingleton<EmailNdebitStore>();

UI Extensions

Three BTCPay Server UI extension points are used:

Extension Point View Purpose
store-integrations-nav ClinkStoreNav Add nav link to store sidebar
ln-payment-method-setup-custom LightningSetupCustom Add CLINK to Lightning setup
checkout-end ClinkCheckoutPayment Add ndebit section at checkout

Embedded Resources

Resource Embedded As
Resources/js/* Assembly resource
Resources/css/* Assembly resource
nostr/clink-bridge.bundle.mjs Assembly resource

Publishing

Build Release

dotnet publish -c Release

Output: publish/plugin/

Create .btcpay Package

The .btcpay file is a renamed ZIP containing:

  • BTCPayServer.Plugins.Clink.dll
  • BTCPayServer.Plugins.Clink.pdb (optional)
  • BTCPayServer.Plugins.Clink.deps.json

Version Bump

Update the version in:

  • src/BTCPayServer.Plugins.Clink/BTCPayServer.Plugins.Clink.csproj (line <Version>)
  • src/BTCPayServer.Plugins.Clink/package.json (line "version")