feat(extensions): add extension loader infrastructure (#3)
Some checks are pending
Docker Compose Actions Workflow / test (push) Waiting to run

## Summary

- Adds a modular extension system for Lightning.Pub enabling third-party plugins
- Provides isolated SQLite databases per extension for data safety
- Implements ExtensionContext API for accessing Lightning.Pub services (payments, Nostr, storage)
- Supports RPC method registration with automatic namespacing
- Includes HTTP route handling for protocols like LNURL
- Event routing for payment receipts and Nostr events
- Comprehensive documentation with architecture overview and working examples

## Key Components

- `src/extensions/types.ts` - Core extension interfaces
- `src/extensions/loader.ts` - Extension discovery, loading, and lifecycle management
- `src/extensions/context.ts` - Bridge between extensions and Lightning.Pub services
- `src/extensions/database.ts` - SQLite isolation with WAL mode
- `src/extensions/README.md` - Full documentation with examples

## ExtensionContext API

| Method | Description |
|--------|-------------|
| `getApplication()` | Get application info |
| `createInvoice()` | Create Lightning invoice |
| `payInvoice()` | Pay Lightning invoice |
| `getLnurlPayInfo()` | Get LNURL-pay info for a user (enables Lightning Address/zaps) |
| `sendEncryptedDM()` | Send Nostr DM (NIP-44) |
| `publishNostrEvent()` | Publish Nostr event |
| `registerMethod()` | Register RPC method |
| `onPaymentReceived()` | Subscribe to payment callbacks |
| `onNostrEvent()` | Subscribe to Nostr events |

## Test plan

- [x] Review extension loader code for correctness
- [x] Verify TypeScript compilation succeeds
- [x] Test extension discovery from `src/extensions/` directory
- [x] Test RPC method registration and routing
- [x] Test database isolation between extensions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: boufni95 <boufni95@gmail.com>
Co-authored-by: Patrick Mulligan <patjmulligan@protonmail.com>
Reviewed-on: #3
This commit is contained in:
padreug 2026-04-02 18:47:55 +00:00
parent 72c9872b23
commit 77e5772afd
47 changed files with 10187 additions and 4828 deletions

View file

@ -1,4 +1,4 @@
// @generated by protobuf-ts 2.8.1
// @generated by protobuf-ts 2.11.1
// @generated from protobuf file "chainnotifier.proto" (package "chainrpc", syntax proto3)
// tslint:disable
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
@ -31,7 +31,7 @@ export interface IChainNotifierClient {
* a notification is sent once the output script confirms in the given
* transaction.
*
* @generated from protobuf rpc: RegisterConfirmationsNtfn(chainrpc.ConfRequest) returns (stream chainrpc.ConfEvent);
* @generated from protobuf rpc: RegisterConfirmationsNtfn
*/
registerConfirmationsNtfn(input: ConfRequest, options?: RpcOptions): ServerStreamingCall<ConfRequest, ConfEvent>;
/**
@ -43,7 +43,7 @@ export interface IChainNotifierClient {
* A client can specify whether the spend request should be for a particular
* outpoint or for an output script by specifying a zero outpoint.
*
* @generated from protobuf rpc: RegisterSpendNtfn(chainrpc.SpendRequest) returns (stream chainrpc.SpendEvent);
* @generated from protobuf rpc: RegisterSpendNtfn
*/
registerSpendNtfn(input: SpendRequest, options?: RpcOptions): ServerStreamingCall<SpendRequest, SpendEvent>;
/**
@ -58,7 +58,7 @@ export interface IChainNotifierClient {
* point. This allows clients to be idempotent by ensuring that they do not
* missing processing a single block within the chain.
*
* @generated from protobuf rpc: RegisterBlockEpochNtfn(chainrpc.BlockEpoch) returns (stream chainrpc.BlockEpoch);
* @generated from protobuf rpc: RegisterBlockEpochNtfn
*/
registerBlockEpochNtfn(input: BlockEpoch, options?: RpcOptions): ServerStreamingCall<BlockEpoch, BlockEpoch>;
}
@ -86,7 +86,7 @@ export class ChainNotifierClient implements IChainNotifierClient, ServiceInfo {
* a notification is sent once the output script confirms in the given
* transaction.
*
* @generated from protobuf rpc: RegisterConfirmationsNtfn(chainrpc.ConfRequest) returns (stream chainrpc.ConfEvent);
* @generated from protobuf rpc: RegisterConfirmationsNtfn
*/
registerConfirmationsNtfn(input: ConfRequest, options?: RpcOptions): ServerStreamingCall<ConfRequest, ConfEvent> {
const method = this.methods[0], opt = this._transport.mergeOptions(options);
@ -101,7 +101,7 @@ export class ChainNotifierClient implements IChainNotifierClient, ServiceInfo {
* A client can specify whether the spend request should be for a particular
* outpoint or for an output script by specifying a zero outpoint.
*
* @generated from protobuf rpc: RegisterSpendNtfn(chainrpc.SpendRequest) returns (stream chainrpc.SpendEvent);
* @generated from protobuf rpc: RegisterSpendNtfn
*/
registerSpendNtfn(input: SpendRequest, options?: RpcOptions): ServerStreamingCall<SpendRequest, SpendEvent> {
const method = this.methods[1], opt = this._transport.mergeOptions(options);
@ -119,7 +119,7 @@ export class ChainNotifierClient implements IChainNotifierClient, ServiceInfo {
* point. This allows clients to be idempotent by ensuring that they do not
* missing processing a single block within the chain.
*
* @generated from protobuf rpc: RegisterBlockEpochNtfn(chainrpc.BlockEpoch) returns (stream chainrpc.BlockEpoch);
* @generated from protobuf rpc: RegisterBlockEpochNtfn
*/
registerBlockEpochNtfn(input: BlockEpoch, options?: RpcOptions): ServerStreamingCall<BlockEpoch, BlockEpoch> {
const method = this.methods[2], opt = this._transport.mergeOptions(options);